summaryrefslogtreecommitdiffstats
path: root/sys/security
diff options
context:
space:
mode:
Diffstat (limited to 'sys/security')
-rw-r--r--sys/security/audit/audit.c683
-rw-r--r--sys/security/audit/audit.h233
-rw-r--r--sys/security/audit/audit_arg.c859
-rw-r--r--sys/security/audit/audit_bsm.c1495
-rw-r--r--sys/security/audit/audit_bsm_errno.c642
-rw-r--r--sys/security/audit/audit_bsm_klib.c580
-rw-r--r--sys/security/audit/audit_bsm_token.c1526
-rw-r--r--sys/security/audit/audit_ioctl.h83
-rw-r--r--sys/security/audit/audit_pipe.c1129
-rw-r--r--sys/security/audit/audit_private.h346
-rw-r--r--sys/security/audit/audit_syscalls.c759
-rw-r--r--sys/security/audit/audit_trigger.c178
-rw-r--r--sys/security/audit/audit_worker.c494
-rw-r--r--sys/security/mac/mac_atalk.c66
-rw-r--r--sys/security/mac/mac_audit.c115
-rw-r--r--sys/security/mac/mac_cred.c213
-rw-r--r--sys/security/mac/mac_framework.c571
-rw-r--r--sys/security/mac/mac_framework.h445
-rw-r--r--sys/security/mac/mac_inet.c425
-rw-r--r--sys/security/mac/mac_inet6.c162
-rw-r--r--sys/security/mac/mac_internal.h345
-rw-r--r--sys/security/mac/mac_label.c151
-rw-r--r--sys/security/mac/mac_net.c460
-rw-r--r--sys/security/mac/mac_pipe.c227
-rw-r--r--sys/security/mac/mac_policy.h1042
-rw-r--r--sys/security/mac/mac_posix_sem.c164
-rw-r--r--sys/security/mac/mac_posix_shm.c151
-rw-r--r--sys/security/mac/mac_priv.c82
-rw-r--r--sys/security/mac/mac_process.c531
-rw-r--r--sys/security/mac/mac_socket.c571
-rw-r--r--sys/security/mac/mac_syscalls.c723
-rw-r--r--sys/security/mac/mac_system.c191
-rw-r--r--sys/security/mac/mac_sysv_msg.c237
-rw-r--r--sys/security/mac/mac_sysv_sem.c143
-rw-r--r--sys/security/mac/mac_sysv_shm.c155
-rw-r--r--sys/security/mac/mac_vfs.c894
-rw-r--r--sys/security/mac_biba/mac_biba.c3569
-rw-r--r--sys/security/mac_biba/mac_biba.h97
-rw-r--r--sys/security/mac_bsdextended/mac_bsdextended.c526
-rw-r--r--sys/security/mac_bsdextended/mac_bsdextended.h114
-rw-r--r--sys/security/mac_bsdextended/ugidfw_internal.h118
-rw-r--r--sys/security/mac_bsdextended/ugidfw_system.c91
-rw-r--r--sys/security/mac_bsdextended/ugidfw_vnode.c297
-rw-r--r--sys/security/mac_ifoff/mac_ifoff.c173
-rw-r--r--sys/security/mac_lomac/mac_lomac.c3076
-rw-r--r--sys/security/mac_lomac/mac_lomac.h89
-rw-r--r--sys/security/mac_mls/mac_mls.c3186
-rw-r--r--sys/security/mac_mls/mac_mls.h102
-rw-r--r--sys/security/mac_none/mac_none.c56
-rw-r--r--sys/security/mac_partition/mac_partition.c319
-rw-r--r--sys/security/mac_partition/mac_partition.h46
-rw-r--r--sys/security/mac_portacl/mac_portacl.c493
-rw-r--r--sys/security/mac_seeotheruids/mac_seeotheruids.c189
-rw-r--r--sys/security/mac_stub/mac_stub.c1824
-rw-r--r--sys/security/mac_test/mac_test.c3163
55 files changed, 34599 insertions, 0 deletions
diff --git a/sys/security/audit/audit.c b/sys/security/audit/audit.c
new file mode 100644
index 0000000..4ea76c6
--- /dev/null
+++ b/sys/security/audit/audit.c
@@ -0,0 +1,683 @@
+/*-
+ * Copyright (c) 1999-2005 Apple Inc.
+ * Copyright (c) 2006-2007 Robert N. M. Watson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/condvar.h>
+#include <sys/conf.h>
+#include <sys/file.h>
+#include <sys/filedesc.h>
+#include <sys/fcntl.h>
+#include <sys/ipc.h>
+#include <sys/kernel.h>
+#include <sys/kthread.h>
+#include <sys/malloc.h>
+#include <sys/mount.h>
+#include <sys/namei.h>
+#include <sys/priv.h>
+#include <sys/proc.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/protosw.h>
+#include <sys/domain.h>
+#include <sys/sysctl.h>
+#include <sys/sysproto.h>
+#include <sys/sysent.h>
+#include <sys/systm.h>
+#include <sys/ucred.h>
+#include <sys/uio.h>
+#include <sys/un.h>
+#include <sys/unistd.h>
+#include <sys/vnode.h>
+
+#include <bsm/audit.h>
+#include <bsm/audit_internal.h>
+#include <bsm/audit_kevents.h>
+
+#include <netinet/in.h>
+#include <netinet/in_pcb.h>
+
+#include <security/audit/audit.h>
+#include <security/audit/audit_private.h>
+
+#include <vm/uma.h>
+
+static uma_zone_t audit_record_zone;
+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");
+
+SYSCTL_NODE(_security, OID_AUTO, audit, CTLFLAG_RW, 0,
+ "TrustedBSD audit controls");
+
+/*
+ * Audit control settings that are set/read by system calls and are hence
+ * non-static.
+ *
+ * Define the audit control flags.
+ */
+int audit_enabled;
+int audit_suspended;
+
+/*
+ * Flags controlling behavior in low storage situations. Should we panic if
+ * a write fails? Should we fail stop if we're out of disk space?
+ */
+int audit_panic_on_write_fail;
+int audit_fail_stop;
+int audit_argv;
+int audit_arge;
+
+/*
+ * Are we currently "failing stop" due to out of disk space?
+ */
+int audit_in_failure;
+
+/*
+ * Global audit statistics.
+ */
+struct audit_fstat audit_fstat;
+
+/*
+ * Preselection mask for non-attributable events.
+ */
+struct au_mask audit_nae_mask;
+
+/*
+ * Mutex to protect global variables shared between various threads and
+ * processes.
+ */
+struct mtx audit_mtx;
+
+/*
+ * Queue of audit records ready for delivery to disk. We insert new records
+ * at the tail, and remove records from the head. Also, a count of the
+ * number of records used for checking queue depth. In addition, a counter
+ * of records that we have allocated but are not yet in the queue, which is
+ * needed to estimate the total size of the combined set of records
+ * outstanding in the system.
+ */
+struct kaudit_queue audit_q;
+size_t audit_q_len;
+size_t audit_pre_q_len;
+
+/*
+ * Audit queue control settings (minimum free, low/high water marks, etc.)
+ */
+struct au_qctrl audit_qctrl;
+
+/*
+ * Condition variable to signal to the worker that it has work to do: either
+ * new records are in the queue, or a log replacement is taking place.
+ */
+struct cv audit_worker_cv;
+
+/*
+ * Condition variable to flag when crossing the low watermark, meaning that
+ * threads blocked due to hitting the high watermark can wake up and continue
+ * to commit records.
+ */
+struct cv audit_watermark_cv;
+
+/*
+ * Condition variable for auditing threads wait on when in fail-stop mode.
+ * Threads wait on this CV forever (and ever), never seeing the light of day
+ * again.
+ */
+static struct cv audit_fail_cv;
+
+/*
+ * Kernel audit information. This will store the current audit address
+ * or host information that the kernel will use when it's generating
+ * audit records. This data is modified by the A_GET{SET}KAUDIT auditon(2)
+ * command.
+ */
+static struct auditinfo_addr audit_kinfo;
+static struct rwlock audit_kinfo_lock;
+
+#define KINFO_LOCK_INIT() rw_init(&audit_kinfo_lock, \
+ "audit_kinfo_lock")
+#define KINFO_RLOCK() rw_rlock(&audit_kinfo_lock)
+#define KINFO_WLOCK() rw_wlock(&audit_kinfo_lock)
+#define KINFO_RUNLOCK() rw_runlock(&audit_kinfo_lock)
+#define KINFO_WUNLOCK() rw_wunlock(&audit_kinfo_lock)
+
+void
+audit_set_kinfo(struct auditinfo_addr *ak)
+{
+
+ KASSERT(ak->ai_termid.at_type == AU_IPv4 ||
+ ak->ai_termid.at_type == AU_IPv6,
+ ("audit_set_kinfo: invalid address type"));
+
+ KINFO_WLOCK();
+ audit_kinfo = *ak;
+ KINFO_WUNLOCK();
+}
+
+void
+audit_get_kinfo(struct auditinfo_addr *ak)
+{
+
+ KASSERT(audit_kinfo.ai_termid.at_type == AU_IPv4 ||
+ audit_kinfo.ai_termid.at_type == AU_IPv6,
+ ("audit_set_kinfo: invalid address type"));
+
+ KINFO_RLOCK();
+ *ak = audit_kinfo;
+ KINFO_RUNLOCK();
+}
+
+/*
+ * Construct an audit record for the passed thread.
+ */
+static int
+audit_record_ctor(void *mem, int size, void *arg, int flags)
+{
+ struct kaudit_record *ar;
+ struct thread *td;
+ struct ucred *cred;
+
+ KASSERT(sizeof(*ar) == size, ("audit_record_ctor: wrong size"));
+
+ td = arg;
+ ar = mem;
+ bzero(ar, sizeof(*ar));
+ ar->k_ar.ar_magic = AUDIT_RECORD_MAGIC;
+ nanotime(&ar->k_ar.ar_starttime);
+
+ /*
+ * Export the subject credential.
+ */
+ cred = td->td_ucred;
+ cru2x(cred, &ar->k_ar.ar_subj_cred);
+ ar->k_ar.ar_subj_ruid = cred->cr_ruid;
+ ar->k_ar.ar_subj_rgid = cred->cr_rgid;
+ ar->k_ar.ar_subj_egid = cred->cr_groups[0];
+ ar->k_ar.ar_subj_auid = cred->cr_audit.ai_auid;
+ ar->k_ar.ar_subj_asid = cred->cr_audit.ai_asid;
+ ar->k_ar.ar_subj_pid = td->td_proc->p_pid;
+ ar->k_ar.ar_subj_amask = cred->cr_audit.ai_mask;
+ ar->k_ar.ar_subj_term_addr = cred->cr_audit.ai_termid;
+ return (0);
+}
+
+static void
+audit_record_dtor(void *mem, int size, void *arg)
+{
+ struct kaudit_record *ar;
+
+ KASSERT(sizeof(*ar) == size, ("audit_record_dtor: wrong size"));
+
+ ar = mem;
+ if (ar->k_ar.ar_arg_upath1 != NULL)
+ free(ar->k_ar.ar_arg_upath1, M_AUDITPATH);
+ if (ar->k_ar.ar_arg_upath2 != NULL)
+ free(ar->k_ar.ar_arg_upath2, M_AUDITPATH);
+ if (ar->k_ar.ar_arg_text != NULL)
+ free(ar->k_ar.ar_arg_text, M_AUDITTEXT);
+ if (ar->k_udata != NULL)
+ free(ar->k_udata, M_AUDITDATA);
+ if (ar->k_ar.ar_arg_argv != NULL)
+ free(ar->k_ar.ar_arg_argv, M_AUDITTEXT);
+ if (ar->k_ar.ar_arg_envv != NULL)
+ free(ar->k_ar.ar_arg_envv, M_AUDITTEXT);
+}
+
+/*
+ * Initialize the Audit subsystem: configuration state, work queue,
+ * synchronization primitives, worker thread, and trigger device node. Also
+ * call into the BSM assembly code to initialize it.
+ */
+static void
+audit_init(void)
+{
+
+ audit_enabled = 0;
+ audit_suspended = 0;
+ audit_panic_on_write_fail = 0;
+ audit_fail_stop = 0;
+ audit_in_failure = 0;
+ audit_argv = 0;
+ audit_arge = 0;
+
+ audit_fstat.af_filesz = 0; /* '0' means unset, unbounded. */
+ audit_fstat.af_currsz = 0;
+ audit_nae_mask.am_success = 0;
+ audit_nae_mask.am_failure = 0;
+
+ TAILQ_INIT(&audit_q);
+ audit_q_len = 0;
+ audit_pre_q_len = 0;
+ audit_qctrl.aq_hiwater = AQ_HIWATER;
+ audit_qctrl.aq_lowater = AQ_LOWATER;
+ audit_qctrl.aq_bufsz = AQ_BUFSZ;
+ audit_qctrl.aq_minfree = AU_FS_MINFREE;
+
+ audit_kinfo.ai_termid.at_type = AU_IPv4;
+ audit_kinfo.ai_termid.at_addr[0] = INADDR_ANY;
+
+ mtx_init(&audit_mtx, "audit_mtx", NULL, MTX_DEF);
+ KINFO_LOCK_INIT();
+ cv_init(&audit_worker_cv, "audit_worker_cv");
+ cv_init(&audit_watermark_cv, "audit_watermark_cv");
+ cv_init(&audit_fail_cv, "audit_fail_cv");
+
+ audit_record_zone = uma_zcreate("audit_record",
+ sizeof(struct kaudit_record), audit_record_ctor,
+ audit_record_dtor, NULL, NULL, UMA_ALIGN_PTR, 0);
+
+ /* Initialize the BSM audit subsystem. */
+ kau_init();
+
+ audit_trigger_init();
+
+ /* Register shutdown handler. */
+ EVENTHANDLER_REGISTER(shutdown_pre_sync, audit_shutdown, NULL,
+ SHUTDOWN_PRI_FIRST);
+
+ /* Start audit worker thread. */
+ audit_worker_init();
+}
+
+SYSINIT(audit_init, SI_SUB_AUDIT, SI_ORDER_FIRST, audit_init, NULL);
+
+/*
+ * Drain the audit queue and close the log at shutdown. Note that this can
+ * be called both from the system shutdown path and also from audit
+ * configuration syscalls, so 'arg' and 'howto' are ignored.
+ *
+ * XXXRW: In FreeBSD 7.x and 8.x, this fails to wait for the record queue to
+ * drain before returning, which could lead to lost records on shutdown.
+ */
+void
+audit_shutdown(void *arg, int howto)
+{
+
+ audit_rotate_vnode(NULL, NULL);
+}
+
+/*
+ * Return the current thread's audit record, if any.
+ */
+struct kaudit_record *
+currecord(void)
+{
+
+ return (curthread->td_ar);
+}
+
+/*
+ * XXXAUDIT: There are a number of races present in the code below due to
+ * release and re-grab of the mutex. The code should be revised to become
+ * slightly less racy.
+ *
+ * XXXAUDIT: Shouldn't there be logic here to sleep waiting on available
+ * pre_q space, suspending the system call until there is room?
+ */
+struct kaudit_record *
+audit_new(int event, struct thread *td)
+{
+ struct kaudit_record *ar;
+ int no_record;
+
+ mtx_lock(&audit_mtx);
+ no_record = (audit_suspended || !audit_enabled);
+ mtx_unlock(&audit_mtx);
+ if (no_record)
+ return (NULL);
+
+ /*
+ * Note: the number of outstanding uncommitted audit records is
+ * limited to the number of concurrent threads servicing system calls
+ * in the kernel.
+ */
+ ar = uma_zalloc_arg(audit_record_zone, td, M_WAITOK);
+ ar->k_ar.ar_event = event;
+
+ mtx_lock(&audit_mtx);
+ audit_pre_q_len++;
+ mtx_unlock(&audit_mtx);
+
+ return (ar);
+}
+
+void
+audit_free(struct kaudit_record *ar)
+{
+
+ uma_zfree(audit_record_zone, ar);
+}
+
+void
+audit_commit(struct kaudit_record *ar, int error, int retval)
+{
+ au_event_t event;
+ au_class_t class;
+ au_id_t auid;
+ int sorf;
+ struct au_mask *aumask;
+
+ if (ar == NULL)
+ return;
+
+ /*
+ * Decide whether to commit the audit record by checking the error
+ * value from the system call and using the appropriate audit mask.
+ */
+ if (ar->k_ar.ar_subj_auid == AU_DEFAUDITID)
+ aumask = &audit_nae_mask;
+ else
+ aumask = &ar->k_ar.ar_subj_amask;
+
+ if (error)
+ sorf = AU_PRS_FAILURE;
+ else
+ sorf = AU_PRS_SUCCESS;
+
+ switch(ar->k_ar.ar_event) {
+ case AUE_OPEN_RWTC:
+ /*
+ * The open syscall always writes a AUE_OPEN_RWTC event;
+ * change it to the proper type of event based on the flags
+ * and the error value.
+ */
+ ar->k_ar.ar_event = audit_flags_and_error_to_openevent(
+ ar->k_ar.ar_arg_fflags, error);
+ break;
+
+ case AUE_SYSCTL:
+ ar->k_ar.ar_event = audit_ctlname_to_sysctlevent(
+ ar->k_ar.ar_arg_ctlname, ar->k_ar.ar_valid_arg);
+ break;
+
+ case AUE_AUDITON:
+ /* Convert the auditon() command to an event. */
+ ar->k_ar.ar_event = auditon_command_event(ar->k_ar.ar_arg_cmd);
+ break;
+ }
+
+ auid = ar->k_ar.ar_subj_auid;
+ event = ar->k_ar.ar_event;
+ class = au_event_class(event);
+
+ ar->k_ar_commit |= AR_COMMIT_KERNEL;
+ if (au_preselect(event, class, aumask, sorf) != 0)
+ ar->k_ar_commit |= AR_PRESELECT_TRAIL;
+ if (audit_pipe_preselect(auid, event, class, sorf,
+ ar->k_ar_commit & AR_PRESELECT_TRAIL) != 0)
+ ar->k_ar_commit |= AR_PRESELECT_PIPE;
+ if ((ar->k_ar_commit & (AR_PRESELECT_TRAIL | AR_PRESELECT_PIPE |
+ AR_PRESELECT_USER_TRAIL | AR_PRESELECT_USER_PIPE)) == 0) {
+ mtx_lock(&audit_mtx);
+ audit_pre_q_len--;
+ mtx_unlock(&audit_mtx);
+ audit_free(ar);
+ return;
+ }
+
+ ar->k_ar.ar_errno = error;
+ ar->k_ar.ar_retval = retval;
+ nanotime(&ar->k_ar.ar_endtime);
+
+ /*
+ * Note: it could be that some records initiated while audit was
+ * enabled should still be committed?
+ */
+ mtx_lock(&audit_mtx);
+ if (audit_suspended || !audit_enabled) {
+ audit_pre_q_len--;
+ mtx_unlock(&audit_mtx);
+ audit_free(ar);
+ return;
+ }
+
+ /*
+ * Constrain the number of committed audit records based on the
+ * configurable parameter.
+ */
+ while (audit_q_len >= audit_qctrl.aq_hiwater)
+ cv_wait(&audit_watermark_cv, &audit_mtx);
+
+ TAILQ_INSERT_TAIL(&audit_q, ar, k_q);
+ audit_q_len++;
+ audit_pre_q_len--;
+ cv_signal(&audit_worker_cv);
+ mtx_unlock(&audit_mtx);
+}
+
+/*
+ * audit_syscall_enter() is called on entry to each system call. It is
+ * responsible for deciding whether or not to audit the call (preselection),
+ * and if so, allocating a per-thread audit record. audit_new() will fill in
+ * basic thread/credential properties.
+ */
+void
+audit_syscall_enter(unsigned short code, struct thread *td)
+{
+ struct au_mask *aumask;
+ au_class_t class;
+ au_event_t event;
+ au_id_t auid;
+
+ KASSERT(td->td_ar == NULL, ("audit_syscall_enter: td->td_ar != NULL"));
+
+ /*
+ * In FreeBSD, each ABI has its own system call table, and hence
+ * mapping of system call codes to audit events. Convert the code to
+ * an audit event identifier using the process system call table
+ * reference. In Darwin, there's only one, so we use the global
+ * symbol for the system call table. No audit record is generated
+ * for bad system calls, as no operation has been performed.
+ */
+ if (code >= td->td_proc->p_sysent->sv_size)
+ return;
+
+ event = td->td_proc->p_sysent->sv_table[code].sy_auevent;
+ if (event == AUE_NULL)
+ return;
+
+ /*
+ * Check which audit mask to use; either the kernel non-attributable
+ * event mask or the process audit mask.
+ */
+ auid = td->td_ucred->cr_audit.ai_auid;
+ if (auid == AU_DEFAUDITID)
+ aumask = &audit_nae_mask;
+ else
+ aumask = &td->td_ucred->cr_audit.ai_mask;
+
+ /*
+ * Allocate an audit record, if preselection allows it, and store in
+ * the thread for later use.
+ */
+ class = au_event_class(event);
+ if (au_preselect(event, class, aumask, AU_PRS_BOTH)) {
+ /*
+ * If we're out of space and need to suspend unprivileged
+ * processes, do that here rather than trying to allocate
+ * another audit record.
+ *
+ * Note: we might wish to be able to continue here in the
+ * future, if the system recovers. That should be possible
+ * by means of checking the condition in a loop around
+ * cv_wait(). It might be desirable to reevaluate whether an
+ * audit record is still required for this event by
+ * re-calling au_preselect().
+ */
+ if (audit_in_failure &&
+ priv_check(td, PRIV_AUDIT_FAILSTOP) != 0) {
+ cv_wait(&audit_fail_cv, &audit_mtx);
+ panic("audit_failing_stop: thread continued");
+ }
+ td->td_ar = audit_new(event, td);
+ } else if (audit_pipe_preselect(auid, event, class, AU_PRS_BOTH, 0))
+ td->td_ar = audit_new(event, td);
+ else
+ td->td_ar = NULL;
+}
+
+/*
+ * audit_syscall_exit() is called from the return of every system call, or in
+ * the event of exit1(), during the execution of exit1(). It is responsible
+ * for committing the audit record, if any, along with return condition.
+ */
+void
+audit_syscall_exit(int error, struct thread *td)
+{
+ int retval;
+
+ /*
+ * Commit the audit record as desired; once we pass the record into
+ * audit_commit(), the memory is owned by the audit subsystem. The
+ * return value from the system call is stored on the user thread.
+ * If there was an error, the return value is set to -1, imitating
+ * the behavior of the cerror routine.
+ */
+ if (error)
+ retval = -1;
+ else
+ retval = td->td_retval[0];
+
+ audit_commit(td->td_ar, error, retval);
+ td->td_ar = NULL;
+}
+
+void
+audit_cred_copy(struct ucred *src, struct ucred *dest)
+{
+
+ bcopy(&src->cr_audit, &dest->cr_audit, sizeof(dest->cr_audit));
+}
+
+void
+audit_cred_destroy(struct ucred *cred)
+{
+
+}
+
+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)
+{
+
+ cred->cr_audit.ai_auid = AU_DEFAUDITID;
+ cred->cr_audit.ai_termid.at_type = AU_IPv4;
+}
+
+void
+audit_cred_proc1(struct ucred *cred)
+{
+
+ cred->cr_audit.ai_auid = AU_DEFAUDITID;
+ cred->cr_audit.ai_termid.at_type = AU_IPv4;
+}
+
+void
+audit_thread_alloc(struct thread *td)
+{
+
+ td->td_ar = NULL;
+}
+
+void
+audit_thread_free(struct thread *td)
+{
+
+ KASSERT(td->td_ar == NULL, ("audit_thread_free: td_ar != NULL"));
+}
+
+void
+audit_proc_coredump(struct thread *td, char *path, int errcode)
+{
+ struct kaudit_record *ar;
+ struct au_mask *aumask;
+ struct ucred *cred;
+ au_class_t class;
+ int ret, sorf;
+ char **pathp;
+ au_id_t auid;
+
+ ret = 0;
+
+ /*
+ * Make sure we are using the correct preselection mask.
+ */
+ cred = td->td_ucred;
+ auid = cred->cr_audit.ai_auid;
+ if (auid == AU_DEFAUDITID)
+ aumask = &audit_nae_mask;
+ else
+ aumask = &cred->cr_audit.ai_mask;
+ /*
+ * It's possible for coredump(9) generation to fail. Make sure that
+ * we handle this case correctly for preselection.
+ */
+ if (errcode != 0)
+ sorf = AU_PRS_FAILURE;
+ else
+ sorf = AU_PRS_SUCCESS;
+ class = au_event_class(AUE_CORE);
+ if (au_preselect(AUE_CORE, class, aumask, sorf) == 0 &&
+ audit_pipe_preselect(auid, AUE_CORE, class, sorf, 0) == 0)
+ return;
+
+ /*
+ * If we are interested in seeing this audit record, allocate it.
+ * Where possible coredump records should contain a pathname and arg32
+ * (signal) tokens.
+ */
+ ar = audit_new(AUE_CORE, td);
+ if (path != NULL) {
+ pathp = &ar->k_ar.ar_arg_upath1;
+ *pathp = malloc(MAXPATHLEN, M_AUDITPATH, M_WAITOK);
+ audit_canon_path(td, path, *pathp);
+ ARG_SET_VALID(ar, ARG_UPATH1);
+ }
+ ar->k_ar.ar_arg_signum = td->td_proc->p_sig;
+ ARG_SET_VALID(ar, ARG_SIGNUM);
+ if (errcode != 0)
+ ret = 1;
+ audit_commit(ar, errcode, ret);
+}
diff --git a/sys/security/audit/audit.h b/sys/security/audit/audit.h
new file mode 100644
index 0000000..14dbcfd
--- /dev/null
+++ b/sys/security/audit/audit.h
@@ -0,0 +1,233 @@
+/*-
+ * Copyright (c) 1999-2005 Apple Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * This header includes function prototypes and type definitions that are
+ * necessary for the kernel as a whole to interact with the audit subsystem.
+ */
+
+#ifndef _SECURITY_AUDIT_KERNEL_H_
+#define _SECURITY_AUDIT_KERNEL_H_
+
+#ifndef _KERNEL
+#error "no user-serviceable parts inside"
+#endif
+
+#include <bsm/audit.h>
+
+#include <sys/file.h>
+#include <sys/sysctl.h>
+
+/*
+ * Audit subsystem condition flags. The audit_enabled flag is set and
+ * removed automatically as a result of configuring log files, and can be
+ * observed but should not be directly manipulated. The audit suspension
+ * flag permits audit to be temporarily disabled without reconfiguring the
+ * audit target.
+ */
+extern int audit_enabled;
+extern int audit_suspended;
+
+/*
+ * Define the masks for the audited arguments.
+ *
+ * XXXRW: These need to remain in audit.h for now because our vnode and name
+ * lookup audit calls rely on passing in flags to indicate which name or
+ * vnode is being logged. These should move to audit_private.h when that is
+ * fixed.
+ */
+#define ARG_EUID 0x0000000000000001ULL
+#define ARG_RUID 0x0000000000000002ULL
+#define ARG_SUID 0x0000000000000004ULL
+#define ARG_EGID 0x0000000000000008ULL
+#define ARG_RGID 0x0000000000000010ULL
+#define ARG_SGID 0x0000000000000020ULL
+#define ARG_PID 0x0000000000000040ULL
+#define ARG_UID 0x0000000000000080ULL
+#define ARG_AUID 0x0000000000000100ULL
+#define ARG_GID 0x0000000000000200ULL
+#define ARG_FD 0x0000000000000400ULL
+#define ARG_POSIX_IPC_PERM 0x0000000000000800ULL
+#define ARG_FFLAGS 0x0000000000001000ULL
+#define ARG_MODE 0x0000000000002000ULL
+#define ARG_DEV 0x0000000000004000ULL
+#define ARG_ADDR 0x0000000000008000ULL
+#define ARG_LEN 0x0000000000010000ULL
+#define ARG_MASK 0x0000000000020000ULL
+#define ARG_SIGNUM 0x0000000000040000ULL
+#define ARG_LOGIN 0x0000000000080000ULL
+#define ARG_SADDRINET 0x0000000000100000ULL
+#define ARG_SADDRINET6 0x0000000000200000ULL
+#define ARG_SADDRUNIX 0x0000000000400000ULL
+#define ARG_TERMID_ADDR 0x0000000000400000ULL
+#define ARG_UNUSED2 0x0000000001000000ULL
+#define ARG_UPATH1 0x0000000002000000ULL
+#define ARG_UPATH2 0x0000000004000000ULL
+#define ARG_TEXT 0x0000000008000000ULL
+#define ARG_VNODE1 0x0000000010000000ULL
+#define ARG_VNODE2 0x0000000020000000ULL
+#define ARG_SVIPC_CMD 0x0000000040000000ULL
+#define ARG_SVIPC_PERM 0x0000000080000000ULL
+#define ARG_SVIPC_ID 0x0000000100000000ULL
+#define ARG_SVIPC_ADDR 0x0000000200000000ULL
+#define ARG_GROUPSET 0x0000000400000000ULL
+#define ARG_CMD 0x0000000800000000ULL
+#define ARG_SOCKINFO 0x0000001000000000ULL
+#define ARG_ASID 0x0000002000000000ULL
+#define ARG_TERMID 0x0000004000000000ULL
+#define ARG_AUDITON 0x0000008000000000ULL
+#define ARG_VALUE 0x0000010000000000ULL
+#define ARG_AMASK 0x0000020000000000ULL
+#define ARG_CTLNAME 0x0000040000000000ULL
+#define ARG_PROCESS 0x0000080000000000ULL
+#define ARG_MACHPORT1 0x0000100000000000ULL
+#define ARG_MACHPORT2 0x0000200000000000ULL
+#define ARG_EXIT 0x0000400000000000ULL
+#define ARG_IOVECSTR 0x0000800000000000ULL
+#define ARG_ARGV 0x0001000000000000ULL
+#define ARG_ENVV 0x0002000000000000ULL
+#define ARG_NONE 0x0000000000000000ULL
+#define ARG_ALL 0xFFFFFFFFFFFFFFFFULL
+
+void audit_syscall_enter(unsigned short code, struct thread *td);
+void audit_syscall_exit(int error, struct thread *td);
+
+/*
+ * The remaining kernel functions are conditionally compiled in as they are
+ * wrapped by a macro, and the macro should be the only place in the source
+ * tree where these functions are referenced.
+ */
+#ifdef AUDIT
+struct ipc_perm;
+struct sockaddr;
+union auditon_udata;
+void audit_arg_addr(void * addr);
+void audit_arg_exit(int status, int retval);
+void audit_arg_len(int len);
+void audit_arg_fd(int fd);
+void audit_arg_fflags(int fflags);
+void audit_arg_gid(gid_t gid);
+void audit_arg_uid(uid_t uid);
+void audit_arg_egid(gid_t egid);
+void audit_arg_euid(uid_t euid);
+void audit_arg_rgid(gid_t rgid);
+void audit_arg_ruid(uid_t ruid);
+void audit_arg_sgid(gid_t sgid);
+void audit_arg_suid(uid_t suid);
+void audit_arg_groupset(gid_t *gidset, u_int gidset_size);
+void audit_arg_login(char *login);
+void audit_arg_ctlname(int *name, int namelen);
+void audit_arg_mask(int mask);
+void audit_arg_mode(mode_t mode);
+void audit_arg_dev(int dev);
+void audit_arg_value(long value);
+void audit_arg_owner(uid_t uid, gid_t gid);
+void audit_arg_pid(pid_t pid);
+void audit_arg_process(struct proc *p);
+void audit_arg_signum(u_int signum);
+void audit_arg_socket(int sodomain, int sotype, int soprotocol);
+void audit_arg_sockaddr(struct thread *td, struct sockaddr *sa);
+void audit_arg_auid(uid_t auid);
+void audit_arg_auditinfo(struct auditinfo *au_info);
+void audit_arg_auditinfo_addr(struct auditinfo_addr *au_info);
+void audit_arg_upath(struct thread *td, char *upath, u_int64_t flags);
+void audit_arg_vnode(struct vnode *vp, u_int64_t flags);
+void audit_arg_text(char *text);
+void audit_arg_cmd(int cmd);
+void audit_arg_svipc_cmd(int cmd);
+void audit_arg_svipc_perm(struct ipc_perm *perm);
+void audit_arg_svipc_id(int id);
+void audit_arg_svipc_addr(void *addr);
+void audit_arg_posix_ipc_perm(uid_t uid, gid_t gid, mode_t mode);
+void audit_arg_auditon(union auditon_udata *udata);
+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_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_proc_coredump(struct thread *td, char *path, int errcode);
+void audit_thread_alloc(struct thread *td);
+void audit_thread_free(struct thread *td);
+
+/*
+ * Define a macro to wrap the audit_arg_* calls by checking the global
+ * audit_enabled flag before performing the actual call.
+ */
+#define AUDIT_ARG(op, args...) do { \
+ if (td->td_ar != NULL) \
+ audit_arg_ ## op (args); \
+} while (0)
+
+#define AUDIT_SYSCALL_ENTER(code, td) do { \
+ if (audit_enabled) { \
+ audit_syscall_enter(code, td); \
+ } \
+} while (0)
+
+/*
+ * Wrap the audit_syscall_exit() function so that it is called only when
+ * auditing is enabled, or we have a audit record on the thread. It is
+ * possible that an audit record was begun before auditing was turned off.
+ */
+#define AUDIT_SYSCALL_EXIT(error, td) do { \
+ if (audit_enabled || (td->td_ar != NULL)) \
+ audit_syscall_exit(error, td); \
+} while (0)
+
+/*
+ * A Macro to wrap the audit_sysclose() function.
+ */
+#define AUDIT_SYSCLOSE(td, fd) do { \
+ if (audit_enabled) \
+ audit_sysclose(td, fd); \
+} while (0)
+
+#else /* !AUDIT */
+
+#define AUDIT_ARG(op, args...) do { \
+} while (0)
+
+#define AUDIT_SYSCALL_ENTER(code, td) do { \
+} while (0)
+
+#define AUDIT_SYSCALL_EXIT(error, td) do { \
+} while (0)
+
+#define AUDIT_SYSCLOSE(p, fd) do { \
+} while (0)
+
+#endif /* AUDIT */
+
+#endif /* !_SECURITY_AUDIT_KERNEL_H_ */
diff --git a/sys/security/audit/audit_arg.c b/sys/security/audit/audit_arg.c
new file mode 100644
index 0000000..2007041
--- /dev/null
+++ b/sys/security/audit/audit_arg.c
@@ -0,0 +1,859 @@
+/*-
+ * Copyright (c) 1999-2005 Apple Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/filedesc.h>
+#include <sys/ipc.h>
+#include <sys/mount.h>
+#include <sys/proc.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/protosw.h>
+#include <sys/domain.h>
+#include <sys/sbuf.h>
+#include <sys/systm.h>
+#include <sys/un.h>
+#include <sys/vnode.h>
+
+#include <netinet/in.h>
+#include <netinet/in_pcb.h>
+
+#include <security/audit/audit.h>
+#include <security/audit/audit_private.h>
+
+/*
+ * Calls to manipulate elements of the audit record structure from system
+ * call code. Macro wrappers will prevent this functions from being entered
+ * if auditing is disabled, avoiding the function call cost. We check the
+ * thread audit record pointer anyway, as the audit condition could change,
+ * and pre-selection may not have allocated an audit record for this event.
+ *
+ * XXXAUDIT: Should we assert, in each case, that this field of the record
+ * hasn't already been filled in?
+ */
+void
+audit_arg_addr(void *addr)
+{
+ struct kaudit_record *ar;
+
+ ar = currecord();
+ if (ar == NULL)
+ return;
+
+ ar->k_ar.ar_arg_addr = addr;
+ ARG_SET_VALID(ar, ARG_ADDR);
+}
+
+void
+audit_arg_exit(int status, int retval)
+{
+ struct kaudit_record *ar;
+
+ ar = currecord();
+ if (ar == NULL)
+ return;
+
+ ar->k_ar.ar_arg_exitstatus = status;
+ ar->k_ar.ar_arg_exitretval = retval;
+ ARG_SET_VALID(ar, ARG_EXIT);
+}
+
+void
+audit_arg_len(int len)
+{
+ struct kaudit_record *ar;
+
+ ar = currecord();
+ if (ar == NULL)
+ return;
+
+ ar->k_ar.ar_arg_len = len;
+ ARG_SET_VALID(ar, ARG_LEN);
+}
+
+void
+audit_arg_fd(int fd)
+{
+ struct kaudit_record *ar;
+
+ ar = currecord();
+ if (ar == NULL)
+ return;
+
+ ar->k_ar.ar_arg_fd = fd;
+ ARG_SET_VALID(ar, ARG_FD);
+}
+
+void
+audit_arg_fflags(int fflags)
+{
+ struct kaudit_record *ar;
+
+ ar = currecord();
+ if (ar == NULL)
+ return;
+
+ ar->k_ar.ar_arg_fflags = fflags;
+ ARG_SET_VALID(ar, ARG_FFLAGS);
+}
+
+void
+audit_arg_gid(gid_t gid)
+{
+ struct kaudit_record *ar;
+
+ ar = currecord();
+ if (ar == NULL)
+ return;
+
+ ar->k_ar.ar_arg_gid = gid;
+ ARG_SET_VALID(ar, ARG_GID);
+}
+
+void
+audit_arg_uid(uid_t uid)
+{
+ struct kaudit_record *ar;
+
+ ar = currecord();
+ if (ar == NULL)
+ return;
+
+ ar->k_ar.ar_arg_uid = uid;
+ ARG_SET_VALID(ar, ARG_UID);
+}
+
+void
+audit_arg_egid(gid_t egid)
+{
+ struct kaudit_record *ar;
+
+ ar = currecord();
+ if (ar == NULL)
+ return;
+
+ ar->k_ar.ar_arg_egid = egid;
+ ARG_SET_VALID(ar, ARG_EGID);
+}
+
+void
+audit_arg_euid(uid_t euid)
+{
+ struct kaudit_record *ar;
+
+ ar = currecord();
+ if (ar == NULL)
+ return;
+
+ ar->k_ar.ar_arg_euid = euid;
+ ARG_SET_VALID(ar, ARG_EUID);
+}
+
+void
+audit_arg_rgid(gid_t rgid)
+{
+ struct kaudit_record *ar;
+
+ ar = currecord();
+ if (ar == NULL)
+ return;
+
+ ar->k_ar.ar_arg_rgid = rgid;
+ ARG_SET_VALID(ar, ARG_RGID);
+}
+
+void
+audit_arg_ruid(uid_t ruid)
+{
+ struct kaudit_record *ar;
+
+ ar = currecord();
+ if (ar == NULL)
+ return;
+
+ ar->k_ar.ar_arg_ruid = ruid;
+ ARG_SET_VALID(ar, ARG_RUID);
+}
+
+void
+audit_arg_sgid(gid_t sgid)
+{
+ struct kaudit_record *ar;
+
+ ar = currecord();
+ if (ar == NULL)
+ return;
+
+ ar->k_ar.ar_arg_sgid = sgid;
+ ARG_SET_VALID(ar, ARG_SGID);
+}
+
+void
+audit_arg_suid(uid_t suid)
+{
+ struct kaudit_record *ar;
+
+ ar = currecord();
+ if (ar == NULL)
+ return;
+
+ ar->k_ar.ar_arg_suid = suid;
+ ARG_SET_VALID(ar, ARG_SUID);
+}
+
+void
+audit_arg_groupset(gid_t *gidset, u_int gidset_size)
+{
+ u_int i;
+ struct kaudit_record *ar;
+
+ ar = currecord();
+ if (ar == NULL)
+ return;
+
+ for (i = 0; i < gidset_size; i++)
+ ar->k_ar.ar_arg_groups.gidset[i] = gidset[i];
+ ar->k_ar.ar_arg_groups.gidset_size = gidset_size;
+ ARG_SET_VALID(ar, ARG_GROUPSET);
+}
+
+void
+audit_arg_login(char *login)
+{
+ struct kaudit_record *ar;
+
+ ar = currecord();
+ if (ar == NULL)
+ return;
+
+ strlcpy(ar->k_ar.ar_arg_login, login, MAXLOGNAME);
+ ARG_SET_VALID(ar, ARG_LOGIN);
+}
+
+void
+audit_arg_ctlname(int *name, int namelen)
+{
+ struct kaudit_record *ar;
+
+ ar = currecord();
+ if (ar == NULL)
+ return;
+
+ bcopy(name, &ar->k_ar.ar_arg_ctlname, namelen * sizeof(int));
+ ar->k_ar.ar_arg_len = namelen;
+ ARG_SET_VALID(ar, ARG_CTLNAME | ARG_LEN);
+}
+
+void
+audit_arg_mask(int mask)
+{
+ struct kaudit_record *ar;
+
+ ar = currecord();
+ if (ar == NULL)
+ return;
+
+ ar->k_ar.ar_arg_mask = mask;
+ ARG_SET_VALID(ar, ARG_MASK);
+}
+
+void
+audit_arg_mode(mode_t mode)
+{
+ struct kaudit_record *ar;
+
+ ar = currecord();
+ if (ar == NULL)
+ return;
+
+ ar->k_ar.ar_arg_mode = mode;
+ ARG_SET_VALID(ar, ARG_MODE);
+}
+
+void
+audit_arg_dev(int dev)
+{
+ struct kaudit_record *ar;
+
+ ar = currecord();
+ if (ar == NULL)
+ return;
+
+ ar->k_ar.ar_arg_dev = dev;
+ ARG_SET_VALID(ar, ARG_DEV);
+}
+
+void
+audit_arg_value(long value)
+{
+ struct kaudit_record *ar;
+
+ ar = currecord();
+ if (ar == NULL)
+ return;
+
+ ar->k_ar.ar_arg_value = value;
+ ARG_SET_VALID(ar, ARG_VALUE);
+}
+
+void
+audit_arg_owner(uid_t uid, gid_t gid)
+{
+ struct kaudit_record *ar;
+
+ ar = currecord();
+ if (ar == NULL)
+ return;
+
+ ar->k_ar.ar_arg_uid = uid;
+ ar->k_ar.ar_arg_gid = gid;
+ ARG_SET_VALID(ar, ARG_UID | ARG_GID);
+}
+
+void
+audit_arg_pid(pid_t pid)
+{
+ struct kaudit_record *ar;
+
+ ar = currecord();
+ if (ar == NULL)
+ return;
+
+ ar->k_ar.ar_arg_pid = pid;
+ ARG_SET_VALID(ar, ARG_PID);
+}
+
+void
+audit_arg_process(struct proc *p)
+{
+ struct kaudit_record *ar;
+ struct ucred *cred;
+
+ KASSERT(p != NULL, ("audit_arg_process: p == NULL"));
+
+ PROC_LOCK_ASSERT(p, MA_OWNED);
+
+ ar = currecord();
+ if (ar == NULL)
+ return;
+
+ cred = p->p_ucred;
+ ar->k_ar.ar_arg_auid = cred->cr_audit.ai_auid;
+ ar->k_ar.ar_arg_euid = cred->cr_uid;
+ ar->k_ar.ar_arg_egid = cred->cr_groups[0];
+ ar->k_ar.ar_arg_ruid = cred->cr_ruid;
+ ar->k_ar.ar_arg_rgid = cred->cr_rgid;
+ ar->k_ar.ar_arg_asid = cred->cr_audit.ai_asid;
+ ar->k_ar.ar_arg_termid_addr = cred->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);
+}
+
+void
+audit_arg_signum(u_int signum)
+{
+ struct kaudit_record *ar;
+
+ ar = currecord();
+ if (ar == NULL)
+ return;
+
+ ar->k_ar.ar_arg_signum = signum;
+ ARG_SET_VALID(ar, ARG_SIGNUM);
+}
+
+void
+audit_arg_socket(int sodomain, int sotype, int soprotocol)
+{
+ struct kaudit_record *ar;
+
+ ar = currecord();
+ if (ar == NULL)
+ return;
+
+ ar->k_ar.ar_arg_sockinfo.so_domain = sodomain;
+ ar->k_ar.ar_arg_sockinfo.so_type = sotype;
+ ar->k_ar.ar_arg_sockinfo.so_protocol = soprotocol;
+ ARG_SET_VALID(ar, ARG_SOCKINFO);
+}
+
+void
+audit_arg_sockaddr(struct thread *td, struct sockaddr *sa)
+{
+ struct kaudit_record *ar;
+
+ KASSERT(td != NULL, ("audit_arg_sockaddr: td == NULL"));
+ KASSERT(sa != NULL, ("audit_arg_sockaddr: sa == NULL"));
+
+ ar = currecord();
+ if (ar == NULL)
+ return;
+
+ bcopy(sa, &ar->k_ar.ar_arg_sockaddr, sa->sa_len);
+ switch (sa->sa_family) {
+ case AF_INET:
+ ARG_SET_VALID(ar, ARG_SADDRINET);
+ break;
+
+ case AF_INET6:
+ ARG_SET_VALID(ar, ARG_SADDRINET6);
+ break;
+
+ case AF_UNIX:
+ audit_arg_upath(td, ((struct sockaddr_un *)sa)->sun_path,
+ ARG_UPATH1);
+ ARG_SET_VALID(ar, ARG_SADDRUNIX);
+ break;
+ /* XXXAUDIT: default:? */
+ }
+}
+
+void
+audit_arg_auid(uid_t auid)
+{
+ struct kaudit_record *ar;
+
+ ar = currecord();
+ if (ar == NULL)
+ return;
+
+ ar->k_ar.ar_arg_auid = auid;
+ ARG_SET_VALID(ar, ARG_AUID);
+}
+
+void
+audit_arg_auditinfo(struct auditinfo *au_info)
+{
+ struct kaudit_record *ar;
+
+ ar = currecord();
+ if (ar == NULL)
+ return;
+
+ ar->k_ar.ar_arg_auid = au_info->ai_auid;
+ ar->k_ar.ar_arg_asid = au_info->ai_asid;
+ ar->k_ar.ar_arg_amask.am_success = au_info->ai_mask.am_success;
+ ar->k_ar.ar_arg_amask.am_failure = au_info->ai_mask.am_failure;
+ ar->k_ar.ar_arg_termid.port = au_info->ai_termid.port;
+ ar->k_ar.ar_arg_termid.machine = au_info->ai_termid.machine;
+ ARG_SET_VALID(ar, ARG_AUID | ARG_ASID | ARG_AMASK | ARG_TERMID);
+}
+
+void
+audit_arg_auditinfo_addr(struct auditinfo_addr *au_info)
+{
+ struct kaudit_record *ar;
+
+ ar = currecord();
+ if (ar == NULL)
+ return;
+
+ ar->k_ar.ar_arg_auid = au_info->ai_auid;
+ ar->k_ar.ar_arg_asid = au_info->ai_asid;
+ ar->k_ar.ar_arg_amask.am_success = au_info->ai_mask.am_success;
+ ar->k_ar.ar_arg_amask.am_failure = au_info->ai_mask.am_failure;
+ ar->k_ar.ar_arg_termid_addr.at_type = au_info->ai_termid.at_type;
+ ar->k_ar.ar_arg_termid_addr.at_port = au_info->ai_termid.at_port;
+ ar->k_ar.ar_arg_termid_addr.at_addr[0] = au_info->ai_termid.at_addr[0];
+ ar->k_ar.ar_arg_termid_addr.at_addr[1] = au_info->ai_termid.at_addr[1];
+ ar->k_ar.ar_arg_termid_addr.at_addr[2] = au_info->ai_termid.at_addr[2];
+ ar->k_ar.ar_arg_termid_addr.at_addr[3] = au_info->ai_termid.at_addr[3];
+ ARG_SET_VALID(ar, ARG_AUID | ARG_ASID | ARG_AMASK | ARG_TERMID_ADDR);
+}
+
+void
+audit_arg_text(char *text)
+{
+ struct kaudit_record *ar;
+
+ KASSERT(text != NULL, ("audit_arg_text: text == NULL"));
+
+ ar = currecord();
+ if (ar == NULL)
+ return;
+
+ /* Invalidate the text string */
+ ar->k_ar.ar_valid_arg &= (ARG_ALL ^ ARG_TEXT);
+
+ if (ar->k_ar.ar_arg_text == NULL)
+ ar->k_ar.ar_arg_text = malloc(MAXPATHLEN, M_AUDITTEXT,
+ M_WAITOK);
+
+ strncpy(ar->k_ar.ar_arg_text, text, MAXPATHLEN);
+ ARG_SET_VALID(ar, ARG_TEXT);
+}
+
+void
+audit_arg_cmd(int cmd)
+{
+ struct kaudit_record *ar;
+
+ ar = currecord();
+ if (ar == NULL)
+ return;
+
+ ar->k_ar.ar_arg_cmd = cmd;
+ ARG_SET_VALID(ar, ARG_CMD);
+}
+
+void
+audit_arg_svipc_cmd(int cmd)
+{
+ struct kaudit_record *ar;
+
+ ar = currecord();
+ if (ar == NULL)
+ return;
+
+ ar->k_ar.ar_arg_svipc_cmd = cmd;
+ ARG_SET_VALID(ar, ARG_SVIPC_CMD);
+}
+
+void
+audit_arg_svipc_perm(struct ipc_perm *perm)
+{
+ struct kaudit_record *ar;
+
+ ar = currecord();
+ if (ar == NULL)
+ return;
+
+ bcopy(perm, &ar->k_ar.ar_arg_svipc_perm,
+ sizeof(ar->k_ar.ar_arg_svipc_perm));
+ ARG_SET_VALID(ar, ARG_SVIPC_PERM);
+}
+
+void
+audit_arg_svipc_id(int id)
+{
+ struct kaudit_record *ar;
+
+ ar = currecord();
+ if (ar == NULL)
+ return;
+
+ ar->k_ar.ar_arg_svipc_id = id;
+ ARG_SET_VALID(ar, ARG_SVIPC_ID);
+}
+
+void
+audit_arg_svipc_addr(void * addr)
+{
+ struct kaudit_record *ar;
+
+ ar = currecord();
+ if (ar == NULL)
+ return;
+
+ ar->k_ar.ar_arg_svipc_addr = addr;
+ ARG_SET_VALID(ar, ARG_SVIPC_ADDR);
+}
+
+void
+audit_arg_posix_ipc_perm(uid_t uid, gid_t gid, mode_t mode)
+{
+ struct kaudit_record *ar;
+
+ ar = currecord();
+ if (ar == NULL)
+ return;
+
+ ar->k_ar.ar_arg_pipc_perm.pipc_uid = uid;
+ ar->k_ar.ar_arg_pipc_perm.pipc_gid = gid;
+ ar->k_ar.ar_arg_pipc_perm.pipc_mode = mode;
+ ARG_SET_VALID(ar, ARG_POSIX_IPC_PERM);
+}
+
+void
+audit_arg_auditon(union auditon_udata *udata)
+{
+ struct kaudit_record *ar;
+
+ ar = currecord();
+ if (ar == NULL)
+ return;
+
+ bcopy((void *)udata, &ar->k_ar.ar_arg_auditon,
+ sizeof(ar->k_ar.ar_arg_auditon));
+ ARG_SET_VALID(ar, ARG_AUDITON);
+}
+
+/*
+ * Audit information about a file, either the file's vnode info, or its
+ * socket address info.
+ */
+void
+audit_arg_file(struct proc *p, struct file *fp)
+{
+ struct kaudit_record *ar;
+ struct socket *so;
+ struct inpcb *pcb;
+ struct vnode *vp;
+ int vfslocked;
+
+ ar = currecord();
+ if (ar == NULL)
+ return;
+
+ switch (fp->f_type) {
+ case DTYPE_VNODE:
+ case DTYPE_FIFO:
+ /*
+ * XXXAUDIT: Only possibly to record as first vnode?
+ */
+ vp = fp->f_vnode;
+ vfslocked = VFS_LOCK_GIANT(vp->v_mount);
+ vn_lock(vp, LK_SHARED | LK_RETRY);
+ audit_arg_vnode(vp, ARG_VNODE1);
+ VOP_UNLOCK(vp, 0);
+ VFS_UNLOCK_GIANT(vfslocked);
+ break;
+
+ case DTYPE_SOCKET:
+ so = (struct socket *)fp->f_data;
+ if (INP_CHECK_SOCKAF(so, PF_INET)) {
+ SOCK_LOCK(so);
+ ar->k_ar.ar_arg_sockinfo.so_type =
+ so->so_type;
+ ar->k_ar.ar_arg_sockinfo.so_domain =
+ INP_SOCKAF(so);
+ ar->k_ar.ar_arg_sockinfo.so_protocol =
+ so->so_proto->pr_protocol;
+ SOCK_UNLOCK(so);
+ pcb = (struct inpcb *)so->so_pcb;
+ INP_RLOCK(pcb);
+ ar->k_ar.ar_arg_sockinfo.so_raddr =
+ pcb->inp_faddr.s_addr;
+ ar->k_ar.ar_arg_sockinfo.so_laddr =
+ pcb->inp_laddr.s_addr;
+ ar->k_ar.ar_arg_sockinfo.so_rport =
+ pcb->inp_fport;
+ ar->k_ar.ar_arg_sockinfo.so_lport =
+ pcb->inp_lport;
+ INP_RUNLOCK(pcb);
+ ARG_SET_VALID(ar, ARG_SOCKINFO);
+ }
+ break;
+
+ default:
+ /* XXXAUDIT: else? */
+ break;
+ }
+}
+
+/*
+ * Store a path as given by the user process for auditing into the audit
+ * record stored on the user thread. This function will allocate the memory
+ * to store the path info if not already available. This memory will be
+ * freed when the audit record is freed.
+ *
+ * XXXAUDIT: Possibly assert that the memory isn't already allocated?
+ */
+void
+audit_arg_upath(struct thread *td, char *upath, u_int64_t flag)
+{
+ struct kaudit_record *ar;
+ char **pathp;
+
+ KASSERT(td != NULL, ("audit_arg_upath: td == NULL"));
+ KASSERT(upath != NULL, ("audit_arg_upath: upath == NULL"));
+
+ ar = currecord();
+ if (ar == NULL)
+ return;
+
+ KASSERT((flag == ARG_UPATH1) || (flag == ARG_UPATH2),
+ ("audit_arg_upath: flag %llu", (unsigned long long)flag));
+ KASSERT((flag != ARG_UPATH1) || (flag != ARG_UPATH2),
+ ("audit_arg_upath: flag %llu", (unsigned long long)flag));
+
+ if (flag == ARG_UPATH1)
+ pathp = &ar->k_ar.ar_arg_upath1;
+ else
+ pathp = &ar->k_ar.ar_arg_upath2;
+
+ if (*pathp == NULL)
+ *pathp = malloc(MAXPATHLEN, M_AUDITPATH, M_WAITOK);
+
+ audit_canon_path(td, upath, *pathp);
+
+ ARG_SET_VALID(ar, flag);
+}
+
+/*
+ * Function to save the path and vnode attr information into the audit
+ * record.
+ *
+ * It is assumed that the caller will hold any vnode locks necessary to
+ * perform a VOP_GETATTR() on the passed vnode.
+ *
+ * XXX: The attr code is very similar to vfs_vnops.c:vn_stat(), but always
+ * provides access to the generation number as we need that to construct the
+ * BSM file ID.
+ *
+ * XXX: We should accept the process argument from the caller, since it's
+ * very likely they already have a reference.
+ *
+ * XXX: Error handling in this function is poor.
+ *
+ * XXXAUDIT: Possibly KASSERT the path pointer is NULL?
+ */
+void
+audit_arg_vnode(struct vnode *vp, u_int64_t flags)
+{
+ struct kaudit_record *ar;
+ struct vattr vattr;
+ int error;
+ struct vnode_au_info *vnp;
+
+ KASSERT(vp != NULL, ("audit_arg_vnode: vp == NULL"));
+ KASSERT((flags == ARG_VNODE1) || (flags == ARG_VNODE2),
+ ("audit_arg_vnode: flags %jd", (intmax_t)flags));
+
+ /*
+ * Assume that if the caller is calling audit_arg_vnode() on a
+ * non-MPSAFE vnode, then it will have acquired Giant.
+ */
+ VFS_ASSERT_GIANT(vp->v_mount);
+ ASSERT_VOP_LOCKED(vp, "audit_arg_vnode");
+
+ ar = currecord();
+ if (ar == NULL)
+ return;
+
+ /*
+ * XXXAUDIT: The below clears, and then resets the flags for valid
+ * arguments. Ideally, either the new vnode is used, or the old one
+ * would be.
+ */
+ if (flags & ARG_VNODE1) {
+ ar->k_ar.ar_valid_arg &= (ARG_ALL ^ ARG_VNODE1);
+ vnp = &ar->k_ar.ar_arg_vnode1;
+ } else {
+ ar->k_ar.ar_valid_arg &= (ARG_ALL ^ ARG_VNODE2);
+ vnp = &ar->k_ar.ar_arg_vnode2;
+ }
+
+ error = VOP_GETATTR(vp, &vattr, curthread->td_ucred);
+ if (error) {
+ /* XXX: How to handle this case? */
+ return;
+ }
+
+ vnp->vn_mode = vattr.va_mode;
+ vnp->vn_uid = vattr.va_uid;
+ vnp->vn_gid = vattr.va_gid;
+ vnp->vn_dev = vattr.va_rdev;
+ vnp->vn_fsid = vattr.va_fsid;
+ vnp->vn_fileid = vattr.va_fileid;
+ vnp->vn_gen = vattr.va_gen;
+ if (flags & ARG_VNODE1)
+ ARG_SET_VALID(ar, ARG_VNODE1);
+ else
+ ARG_SET_VALID(ar, ARG_VNODE2);
+}
+
+/*
+ * Audit the argument strings passed to exec.
+ */
+void
+audit_arg_argv(char *argv, int argc, int length)
+{
+ struct kaudit_record *ar;
+
+ if (audit_argv == 0)
+ return;
+
+ ar = currecord();
+ if (ar == NULL)
+ return;
+
+ ar->k_ar.ar_arg_argv = malloc(length, M_AUDITTEXT, M_WAITOK);
+ bcopy(argv, ar->k_ar.ar_arg_argv, length);
+ ar->k_ar.ar_arg_argc = argc;
+ ARG_SET_VALID(ar, ARG_ARGV);
+}
+
+/*
+ * Audit the environment strings passed to exec.
+ */
+void
+audit_arg_envv(char *envv, int envc, int length)
+{
+ struct kaudit_record *ar;
+
+ if (audit_arge == 0)
+ return;
+
+ ar = currecord();
+ if (ar == NULL)
+ return;
+
+ ar->k_ar.ar_arg_envv = malloc(length, M_AUDITTEXT, M_WAITOK);
+ bcopy(envv, ar->k_ar.ar_arg_envv, length);
+ ar->k_ar.ar_arg_envc = envc;
+ ARG_SET_VALID(ar, ARG_ENVV);
+}
+
+/*
+ * The close() system call uses it's own audit call to capture the path/vnode
+ * information because those pieces are not easily obtained within the system
+ * call itself.
+ */
+void
+audit_sysclose(struct thread *td, int fd)
+{
+ struct kaudit_record *ar;
+ struct vnode *vp;
+ struct file *fp;
+ int vfslocked;
+
+ KASSERT(td != NULL, ("audit_sysclose: td == NULL"));
+
+ ar = currecord();
+ if (ar == NULL)
+ return;
+
+ audit_arg_fd(fd);
+
+ if (getvnode(td->td_proc->p_fd, fd, &fp) != 0)
+ return;
+
+ vp = fp->f_vnode;
+ vfslocked = VFS_LOCK_GIANT(vp->v_mount);
+ vn_lock(vp, LK_SHARED | LK_RETRY);
+ audit_arg_vnode(vp, ARG_VNODE1);
+ VOP_UNLOCK(vp, 0);
+ VFS_UNLOCK_GIANT(vfslocked);
+ fdrop(fp, td);
+}
diff --git a/sys/security/audit/audit_bsm.c b/sys/security/audit/audit_bsm.c
new file mode 100644
index 0000000..1ddb8be
--- /dev/null
+++ b/sys/security/audit/audit_bsm.c
@@ -0,0 +1,1495 @@
+/*
+ * Copyright (c) 1999-2005 Apple Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/vnode.h>
+#include <sys/ipc.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/mutex.h>
+#include <sys/socket.h>
+#include <sys/extattr.h>
+#include <sys/fcntl.h>
+#include <sys/user.h>
+#include <sys/systm.h>
+
+#include <bsm/audit.h>
+#include <bsm/audit_internal.h>
+#include <bsm/audit_record.h>
+#include <bsm/audit_kevents.h>
+
+#include <security/audit/audit.h>
+#include <security/audit/audit_private.h>
+
+#include <netinet/in_systm.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+
+MALLOC_DEFINE(M_AUDITBSM, "audit_bsm", "Audit BSM data");
+
+static void audit_sys_auditon(struct audit_record *ar,
+ struct au_record *rec);
+
+/*
+ * Initialize the BSM auditing subsystem.
+ */
+void
+kau_init(void)
+{
+
+ au_evclassmap_init();
+}
+
+/*
+ * This call reserves memory for the audit record. Memory must be guaranteed
+ * before any auditable event can be generated. The au_record structure
+ * maintains a reference to the memory allocated above and also the list of
+ * tokens associated with this record.
+ */
+static struct au_record *
+kau_open(void)
+{
+ struct au_record *rec;
+
+ rec = malloc(sizeof(*rec), M_AUDITBSM, M_WAITOK);
+ rec->data = NULL;
+ TAILQ_INIT(&rec->token_q);
+ rec->len = 0;
+ rec->used = 1;
+
+ return (rec);
+}
+
+/*
+ * Store the token with the record descriptor.
+ */
+static void
+kau_write(struct au_record *rec, struct au_token *tok)
+{
+
+ KASSERT(tok != NULL, ("kau_write: tok == NULL"));
+
+ TAILQ_INSERT_TAIL(&rec->token_q, tok, tokens);
+ rec->len += tok->len;
+}
+
+/*
+ * Close out the audit record by adding the header token, identifying any
+ * missing tokens. Write out the tokens to the record memory.
+ */
+static void
+kau_close(struct au_record *rec, struct timespec *ctime, short event)
+{
+ u_char *dptr;
+ size_t tot_rec_size;
+ token_t *cur, *hdr, *trail;
+ struct timeval tm;
+ size_t hdrsize;
+ struct auditinfo_addr ak;
+ struct in6_addr *ap;
+
+ audit_get_kinfo(&ak);
+ hdrsize = 0;
+ switch (ak.ai_termid.at_type) {
+ case AU_IPv4:
+ hdrsize = (ak.ai_termid.at_addr[0] == INADDR_ANY) ?
+ AUDIT_HEADER_SIZE : AUDIT_HEADER_EX_SIZE(&ak);
+ break;
+ case AU_IPv6:
+ ap = (struct in6_addr *)&ak.ai_termid.at_addr[0];
+ hdrsize = (IN6_IS_ADDR_UNSPECIFIED(ap)) ? AUDIT_HEADER_SIZE :
+ AUDIT_HEADER_EX_SIZE(&ak);
+ break;
+ default:
+ panic("kau_close: invalid address family");
+ }
+ tot_rec_size = rec->len + hdrsize + AUDIT_TRAILER_SIZE;
+ rec->data = malloc(tot_rec_size, M_AUDITBSM, M_WAITOK | M_ZERO);
+
+ tm.tv_usec = ctime->tv_nsec / 1000;
+ tm.tv_sec = ctime->tv_sec;
+ if (hdrsize != AUDIT_HEADER_SIZE)
+ hdr = au_to_header32_ex_tm(tot_rec_size, event, 0, tm, &ak);
+ else
+ hdr = au_to_header32_tm(tot_rec_size, event, 0, tm);
+ TAILQ_INSERT_HEAD(&rec->token_q, hdr, tokens);
+
+ trail = au_to_trailer(tot_rec_size);
+ TAILQ_INSERT_TAIL(&rec->token_q, trail, tokens);
+
+ rec->len = tot_rec_size;
+ dptr = rec->data;
+ TAILQ_FOREACH(cur, &rec->token_q, tokens) {
+ memcpy(dptr, cur->t_data, cur->len);
+ dptr += cur->len;
+ }
+}
+
+/*
+ * Free a BSM audit record by releasing all the tokens and clearing the audit
+ * record information.
+ */
+void
+kau_free(struct au_record *rec)
+{
+ struct au_token *tok;
+
+ /* Free the token list. */
+ while ((tok = TAILQ_FIRST(&rec->token_q))) {
+ TAILQ_REMOVE(&rec->token_q, tok, tokens);
+ free(tok->t_data, M_AUDITBSM);
+ free(tok, M_AUDITBSM);
+ }
+
+ rec->used = 0;
+ rec->len = 0;
+ free(rec->data, M_AUDITBSM);
+ free(rec, M_AUDITBSM);
+}
+
+/*
+ * XXX: May want turn some (or all) of these macros into functions in order
+ * to reduce the generated code size.
+ *
+ * XXXAUDIT: These macros assume that 'kar', 'ar', 'rec', and 'tok' in the
+ * caller are OK with this.
+ */
+#define UPATH1_TOKENS do { \
+ if (ARG_IS_VALID(kar, ARG_UPATH1)) { \
+ tok = au_to_path(ar->ar_arg_upath1); \
+ kau_write(rec, tok); \
+ } \
+} while (0)
+
+#define UPATH2_TOKENS do { \
+ if (ARG_IS_VALID(kar, ARG_UPATH2)) { \
+ tok = au_to_path(ar->ar_arg_upath2); \
+ kau_write(rec, tok); \
+ } \
+} while (0)
+
+#define VNODE1_TOKENS do { \
+ if (ARG_IS_VALID(kar, ARG_VNODE1)) { \
+ tok = au_to_attr32(&ar->ar_arg_vnode1); \
+ kau_write(rec, tok); \
+ } \
+} while (0)
+
+#define UPATH1_VNODE1_TOKENS do { \
+ if (ARG_IS_VALID(kar, ARG_UPATH1)) { \
+ UPATH1_TOKENS; \
+ } \
+ if (ARG_IS_VALID(kar, ARG_VNODE1)) { \
+ tok = au_to_attr32(&ar->ar_arg_vnode1); \
+ kau_write(rec, tok); \
+ } \
+} while (0)
+
+#define VNODE2_TOKENS do { \
+ if (ARG_IS_VALID(kar, ARG_VNODE2)) { \
+ tok = au_to_attr32(&ar->ar_arg_vnode2); \
+ kau_write(rec, tok); \
+ } \
+} while (0)
+
+#define FD_VNODE1_TOKENS do { \
+ if (ARG_IS_VALID(kar, ARG_VNODE1)) { \
+ if (ARG_IS_VALID(kar, ARG_FD)) { \
+ tok = au_to_arg32(1, "fd", ar->ar_arg_fd); \
+ kau_write(rec, tok); \
+ } \
+ tok = au_to_attr32(&ar->ar_arg_vnode1); \
+ kau_write(rec, tok); \
+ } else { \
+ if (ARG_IS_VALID(kar, ARG_FD)) { \
+ tok = au_to_arg32(1, "non-file: fd", \
+ ar->ar_arg_fd); \
+ kau_write(rec, tok); \
+ } \
+ } \
+} while (0)
+
+#define PROCESS_PID_TOKENS(argn) do { \
+ if ((ar->ar_arg_pid > 0) /* Reference a single process */ \
+ && (ARG_IS_VALID(kar, ARG_PROCESS))) { \
+ tok = au_to_process32_ex(ar->ar_arg_auid, \
+ ar->ar_arg_euid, ar->ar_arg_egid, \
+ ar->ar_arg_ruid, ar->ar_arg_rgid, \
+ ar->ar_arg_pid, ar->ar_arg_asid, \
+ &ar->ar_arg_termid_addr); \
+ kau_write(rec, tok); \
+ } else if (ARG_IS_VALID(kar, ARG_PID)) { \
+ tok = au_to_arg32(argn, "process", ar->ar_arg_pid); \
+ kau_write(rec, tok); \
+ } \
+} while (0)
+
+#define EXTATTR_TOKENS do { \
+ if (ARG_IS_VALID(kar, ARG_VALUE)) { \
+ switch (ar->ar_arg_value) { \
+ case EXTATTR_NAMESPACE_USER: \
+ tok = au_to_text(EXTATTR_NAMESPACE_USER_STRING);\
+ break; \
+ case EXTATTR_NAMESPACE_SYSTEM: \
+ tok = au_to_text(EXTATTR_NAMESPACE_SYSTEM_STRING);\
+ break; \
+ default: \
+ tok = au_to_arg32(3, "attrnamespace", \
+ ar->ar_arg_value); \
+ break; \
+ } \
+ kau_write(rec, tok); \
+ } \
+ /* attrname is in the text field */ \
+ if (ARG_IS_VALID(kar, ARG_TEXT)) { \
+ tok = au_to_text(ar->ar_arg_text); \
+ kau_write(rec, tok); \
+ } \
+} while (0)
+
+/*
+ * Implement auditing for the auditon() system call. The audit tokens that
+ * are generated depend on the command that was sent into the auditon()
+ * system call.
+ */
+static void
+audit_sys_auditon(struct audit_record *ar, struct au_record *rec)
+{
+ struct au_token *tok;
+
+ switch (ar->ar_arg_cmd) {
+ case A_SETPOLICY:
+ if (sizeof(ar->ar_arg_auditon.au_flags) > 4)
+ tok = au_to_arg64(1, "policy",
+ ar->ar_arg_auditon.au_flags);
+ else
+ tok = au_to_arg32(1, "policy",
+ ar->ar_arg_auditon.au_flags);
+ kau_write(rec, tok);
+ break;
+
+ case A_SETKMASK:
+ tok = au_to_arg32(2, "setkmask:as_success",
+ ar->ar_arg_auditon.au_mask.am_success);
+ kau_write(rec, tok);
+ tok = au_to_arg32(2, "setkmask:as_failure",
+ ar->ar_arg_auditon.au_mask.am_failure);
+ kau_write(rec, tok);
+ break;
+
+ case A_SETQCTRL:
+ tok = au_to_arg32(3, "setqctrl:aq_hiwater",
+ ar->ar_arg_auditon.au_qctrl.aq_hiwater);
+ kau_write(rec, tok);
+ tok = au_to_arg32(3, "setqctrl:aq_lowater",
+ ar->ar_arg_auditon.au_qctrl.aq_lowater);
+ kau_write(rec, tok);
+ tok = au_to_arg32(3, "setqctrl:aq_bufsz",
+ ar->ar_arg_auditon.au_qctrl.aq_bufsz);
+ kau_write(rec, tok);
+ tok = au_to_arg32(3, "setqctrl:aq_delay",
+ ar->ar_arg_auditon.au_qctrl.aq_delay);
+ kau_write(rec, tok);
+ tok = au_to_arg32(3, "setqctrl:aq_minfree",
+ ar->ar_arg_auditon.au_qctrl.aq_minfree);
+ kau_write(rec, tok);
+ break;
+
+ case A_SETUMASK:
+ tok = au_to_arg32(3, "setumask:as_success",
+ ar->ar_arg_auditon.au_auinfo.ai_mask.am_success);
+ kau_write(rec, tok);
+ tok = au_to_arg32(3, "setumask:as_failure",
+ ar->ar_arg_auditon.au_auinfo.ai_mask.am_failure);
+ kau_write(rec, tok);
+ break;
+
+ case A_SETSMASK:
+ tok = au_to_arg32(3, "setsmask:as_success",
+ ar->ar_arg_auditon.au_auinfo.ai_mask.am_success);
+ kau_write(rec, tok);
+ tok = au_to_arg32(3, "setsmask:as_failure",
+ ar->ar_arg_auditon.au_auinfo.ai_mask.am_failure);
+ kau_write(rec, tok);
+ break;
+
+ case A_SETCOND:
+ if (sizeof(ar->ar_arg_auditon.au_cond) > 4)
+ tok = au_to_arg64(3, "setcond",
+ ar->ar_arg_auditon.au_cond);
+ else
+ tok = au_to_arg32(3, "setcond",
+ ar->ar_arg_auditon.au_cond);
+ kau_write(rec, tok);
+ break;
+
+ case A_SETCLASS:
+ tok = au_to_arg32(2, "setclass:ec_event",
+ ar->ar_arg_auditon.au_evclass.ec_number);
+ kau_write(rec, tok);
+ tok = au_to_arg32(3, "setclass:ec_class",
+ ar->ar_arg_auditon.au_evclass.ec_class);
+ kau_write(rec, tok);
+ break;
+
+ case A_SETPMASK:
+ tok = au_to_arg32(2, "setpmask:as_success",
+ ar->ar_arg_auditon.au_aupinfo.ap_mask.am_success);
+ kau_write(rec, tok);
+ tok = au_to_arg32(2, "setpmask:as_failure",
+ ar->ar_arg_auditon.au_aupinfo.ap_mask.am_failure);
+ kau_write(rec, tok);
+ break;
+
+ case A_SETFSIZE:
+ tok = au_to_arg32(2, "setfsize:filesize",
+ ar->ar_arg_auditon.au_fstat.af_filesz);
+ kau_write(rec, tok);
+ break;
+
+ default:
+ break;
+ }
+}
+
+/*
+ * Convert an internal kernel audit record to a BSM record and return a
+ * success/failure indicator. The BSM record is passed as an out parameter to
+ * this function.
+ *
+ * Return conditions:
+ * BSM_SUCCESS: The BSM record is valid
+ * BSM_FAILURE: Failure; the BSM record is NULL.
+ * BSM_NOAUDIT: The event is not auditable for BSM; the BSM record is NULL.
+ */
+int
+kaudit_to_bsm(struct kaudit_record *kar, struct au_record **pau)
+{
+ struct au_token *tok, *subj_tok;
+ struct au_record *rec;
+ au_tid_t tid;
+ struct audit_record *ar;
+ int ctr;
+
+ KASSERT(kar != NULL, ("kaudit_to_bsm: kar == NULL"));
+
+ *pau = NULL;
+ ar = &kar->k_ar;
+ rec = kau_open();
+
+ /*
+ * Create the subject token.
+ */
+ switch (ar->ar_subj_term_addr.at_type) {
+ case AU_IPv4:
+ tid.port = ar->ar_subj_term_addr.at_port;
+ tid.machine = ar->ar_subj_term_addr.at_addr[0];
+ subj_tok = au_to_subject32(ar->ar_subj_auid, /* audit ID */
+ ar->ar_subj_cred.cr_uid, /* eff uid */
+ ar->ar_subj_egid, /* eff group id */
+ ar->ar_subj_ruid, /* real uid */
+ ar->ar_subj_rgid, /* real group id */
+ ar->ar_subj_pid, /* process id */
+ ar->ar_subj_asid, /* session ID */
+ &tid);
+ break;
+ case AU_IPv6:
+ subj_tok = au_to_subject32_ex(ar->ar_subj_auid,
+ ar->ar_subj_cred.cr_uid,
+ ar->ar_subj_egid,
+ ar->ar_subj_ruid,
+ ar->ar_subj_rgid,
+ ar->ar_subj_pid,
+ ar->ar_subj_asid,
+ &ar->ar_subj_term_addr);
+ break;
+ default:
+ bzero(&tid, sizeof(tid));
+ subj_tok = au_to_subject32(ar->ar_subj_auid,
+ ar->ar_subj_cred.cr_uid,
+ ar->ar_subj_egid,
+ ar->ar_subj_ruid,
+ ar->ar_subj_rgid,
+ ar->ar_subj_pid,
+ ar->ar_subj_asid,
+ &tid);
+ }
+
+ /*
+ * The logic inside each case fills in the tokens required for the
+ * event, except for the header, trailer, and return tokens. The
+ * header and trailer tokens are added by the kau_close() function.
+ * The return token is added outside of the switch statement.
+ */
+ switch(ar->ar_event) {
+ case AUE_ACCEPT:
+ case AUE_BIND:
+ case AUE_LISTEN:
+ case AUE_CONNECT:
+ case AUE_RECV:
+ case AUE_RECVFROM:
+ case AUE_RECVMSG:
+ case AUE_SEND:
+ case AUE_SENDFILE:
+ case AUE_SENDMSG:
+ case AUE_SENDTO:
+ /*
+ * Socket-related events.
+ */
+ if (ARG_IS_VALID(kar, ARG_FD)) {
+ tok = au_to_arg32(1, "fd", ar->ar_arg_fd);
+ kau_write(rec, tok);
+ }
+ if (ARG_IS_VALID(kar, ARG_SADDRINET)) {
+ tok = au_to_sock_inet((struct sockaddr_in *)
+ &ar->ar_arg_sockaddr);
+ kau_write(rec, tok);
+ }
+ if (ARG_IS_VALID(kar, ARG_SADDRUNIX)) {
+ tok = au_to_sock_unix((struct sockaddr_un *)
+ &ar->ar_arg_sockaddr);
+ kau_write(rec, tok);
+ UPATH1_TOKENS;
+ }
+ /* XXX Need to handle ARG_SADDRINET6 */
+ break;
+
+ case AUE_SOCKET:
+ case AUE_SOCKETPAIR:
+ if (ARG_IS_VALID(kar, ARG_SOCKINFO)) {
+ tok = au_to_arg32(1,"domain",
+ ar->ar_arg_sockinfo.so_domain);
+ kau_write(rec, tok);
+ tok = au_to_arg32(2,"type",
+ ar->ar_arg_sockinfo.so_type);
+ kau_write(rec, tok);
+ tok = au_to_arg32(3,"protocol",
+ ar->ar_arg_sockinfo.so_protocol);
+ kau_write(rec, tok);
+ }
+ break;
+
+ case AUE_SETSOCKOPT:
+ case AUE_SHUTDOWN:
+ if (ARG_IS_VALID(kar, ARG_FD)) {
+ tok = au_to_arg32(1, "fd", ar->ar_arg_fd);
+ kau_write(rec, tok);
+ }
+ break;
+
+ case AUE_ACCT:
+ if (ARG_IS_VALID(kar, ARG_UPATH1)) {
+ UPATH1_VNODE1_TOKENS;
+ } else {
+ tok = au_to_arg32(1, "accounting off", 0);
+ kau_write(rec, tok);
+ }
+ break;
+
+ case AUE_SETAUID:
+ if (ARG_IS_VALID(kar, ARG_AUID)) {
+ tok = au_to_arg32(2, "setauid", ar->ar_arg_auid);
+ kau_write(rec, tok);
+ }
+ break;
+
+ case AUE_SETAUDIT:
+ if (ARG_IS_VALID(kar, ARG_AUID) &&
+ ARG_IS_VALID(kar, ARG_ASID) &&
+ ARG_IS_VALID(kar, ARG_AMASK) &&
+ ARG_IS_VALID(kar, ARG_TERMID)) {
+ tok = au_to_arg32(1, "setaudit:auid",
+ ar->ar_arg_auid);
+ kau_write(rec, tok);
+ tok = au_to_arg32(1, "setaudit:port",
+ ar->ar_arg_termid.port);
+ kau_write(rec, tok);
+ tok = au_to_arg32(1, "setaudit:machine",
+ ar->ar_arg_termid.machine);
+ kau_write(rec, tok);
+ tok = au_to_arg32(1, "setaudit:as_success",
+ ar->ar_arg_amask.am_success);
+ kau_write(rec, tok);
+ tok = au_to_arg32(1, "setaudit:as_failure",
+ ar->ar_arg_amask.am_failure);
+ kau_write(rec, tok);
+ tok = au_to_arg32(1, "setaudit:asid",
+ ar->ar_arg_asid);
+ kau_write(rec, tok);
+ }
+ break;
+
+ case AUE_SETAUDIT_ADDR:
+ if (ARG_IS_VALID(kar, ARG_AUID) &&
+ ARG_IS_VALID(kar, ARG_ASID) &&
+ ARG_IS_VALID(kar, ARG_AMASK) &&
+ ARG_IS_VALID(kar, ARG_TERMID_ADDR)) {
+ tok = au_to_arg32(1, "setaudit_addr:auid",
+ ar->ar_arg_auid);
+ kau_write(rec, tok);
+ tok = au_to_arg32(1, "setaudit_addr:as_success",
+ ar->ar_arg_amask.am_success);
+ kau_write(rec, tok);
+ tok = au_to_arg32(1, "setaudit_addr:as_failure",
+ ar->ar_arg_amask.am_failure);
+ kau_write(rec, tok);
+ tok = au_to_arg32(1, "setaudit_addr:asid",
+ ar->ar_arg_asid);
+ kau_write(rec, tok);
+ tok = au_to_arg32(1, "setaudit_addr:type",
+ ar->ar_arg_termid_addr.at_type);
+ kau_write(rec, tok);
+ tok = au_to_arg32(1, "setaudit_addr:port",
+ ar->ar_arg_termid_addr.at_port);
+ kau_write(rec, tok);
+ if (ar->ar_arg_termid_addr.at_type == AU_IPv6)
+ tok = au_to_in_addr_ex((struct in6_addr *)
+ &ar->ar_arg_termid_addr.at_addr[0]);
+ if (ar->ar_arg_termid_addr.at_type == AU_IPv4)
+ tok = au_to_in_addr((struct in_addr *)
+ &ar->ar_arg_termid_addr.at_addr[0]);
+ kau_write(rec, tok);
+ }
+ break;
+
+ case AUE_AUDITON:
+ /*
+ * For AUDITON commands without own event, audit the cmd.
+ */
+ if (ARG_IS_VALID(kar, ARG_CMD)) {
+ tok = au_to_arg32(1, "cmd", ar->ar_arg_cmd);
+ kau_write(rec, tok);
+ }
+ /* FALLTHROUGH */
+
+ case AUE_AUDITON_GETCAR:
+ case AUE_AUDITON_GETCLASS:
+ case AUE_AUDITON_GETCOND:
+ case AUE_AUDITON_GETCWD:
+ case AUE_AUDITON_GETKMASK:
+ case AUE_AUDITON_GETSTAT:
+ case AUE_AUDITON_GPOLICY:
+ case AUE_AUDITON_GQCTRL:
+ case AUE_AUDITON_SETCLASS:
+ case AUE_AUDITON_SETCOND:
+ case AUE_AUDITON_SETKMASK:
+ case AUE_AUDITON_SETSMASK:
+ case AUE_AUDITON_SETSTAT:
+ case AUE_AUDITON_SETUMASK:
+ case AUE_AUDITON_SPOLICY:
+ case AUE_AUDITON_SQCTRL:
+ if (ARG_IS_VALID(kar, ARG_AUDITON))
+ audit_sys_auditon(ar, rec);
+ break;
+
+ case AUE_AUDITCTL:
+ UPATH1_VNODE1_TOKENS;
+ break;
+
+ case AUE_EXIT:
+ if (ARG_IS_VALID(kar, ARG_EXIT)) {
+ tok = au_to_exit(ar->ar_arg_exitretval,
+ ar->ar_arg_exitstatus);
+ kau_write(rec, tok);
+ }
+ break;
+
+ case AUE_ADJTIME:
+ case AUE_CLOCK_SETTIME:
+ case AUE_AUDIT:
+ case AUE_DUP2:
+ case AUE_GETAUDIT:
+ case AUE_GETAUDIT_ADDR:
+ case AUE_GETAUID:
+ case AUE_GETCWD:
+ case AUE_GETFSSTAT:
+ case AUE_GETRESUID:
+ case AUE_GETRESGID:
+ case AUE_KQUEUE:
+ case AUE_LSEEK:
+ case AUE_MODLOAD:
+ case AUE_MODUNLOAD:
+ case AUE_MSGSYS:
+ case AUE_NFS_SVC:
+ case AUE_NTP_ADJTIME:
+ case AUE_PIPE:
+ case AUE_PROFILE:
+ case AUE_RTPRIO:
+ case AUE_SEMSYS:
+ case AUE_SHMSYS:
+ case AUE_SETPGRP:
+ case AUE_SETRLIMIT:
+ case AUE_SETSID:
+ case AUE_SETTIMEOFDAY:
+ case AUE_SYSARCH:
+
+ /*
+ * Header, subject, and return tokens added at end.
+ */
+ break;
+
+ case AUE_MKFIFO:
+ if (ARG_IS_VALID(kar, ARG_MODE)) {
+ tok = au_to_arg32(2, "mode", ar->ar_arg_mode);
+ kau_write(rec, tok);
+ }
+ /* FALLTHROUGH */
+
+ case AUE_ACCESS:
+ case AUE_CHDIR:
+ case AUE_CHROOT:
+ case AUE_EACCESS:
+ case AUE_GETATTRLIST:
+ case AUE_JAIL:
+ case AUE_LUTIMES:
+ case AUE_NFS_GETFH:
+ case AUE_LSTAT:
+ case AUE_PATHCONF:
+ case AUE_READLINK:
+ case AUE_REVOKE:
+ case AUE_RMDIR:
+ case AUE_SEARCHFS:
+ case AUE_SETATTRLIST:
+ case AUE_STAT:
+ case AUE_STATFS:
+ case AUE_SWAPON:
+ case AUE_SWAPOFF:
+ case AUE_TRUNCATE:
+ case AUE_UNDELETE:
+ case AUE_UNLINK:
+ case AUE_UTIMES:
+ UPATH1_VNODE1_TOKENS;
+ break;
+
+ case AUE_FHSTATFS:
+ case AUE_FHOPEN:
+ case AUE_FHSTAT:
+ /* XXXRW: Need to audit vnode argument. */
+ break;
+
+ case AUE_CHFLAGS:
+ case AUE_LCHFLAGS:
+ if (ARG_IS_VALID(kar, ARG_FFLAGS)) {
+ tok = au_to_arg32(2, "flags", ar->ar_arg_fflags);
+ kau_write(rec, tok);
+ }
+ UPATH1_VNODE1_TOKENS;
+ break;
+
+ case AUE_CHMOD:
+ case AUE_LCHMOD:
+ if (ARG_IS_VALID(kar, ARG_MODE)) {
+ tok = au_to_arg32(2, "new file mode",
+ ar->ar_arg_mode);
+ kau_write(rec, tok);
+ }
+ UPATH1_VNODE1_TOKENS;
+ break;
+
+ case AUE_CHOWN:
+ case AUE_LCHOWN:
+ if (ARG_IS_VALID(kar, ARG_UID)) {
+ tok = au_to_arg32(2, "new file uid", ar->ar_arg_uid);
+ kau_write(rec, tok);
+ }
+ if (ARG_IS_VALID(kar, ARG_GID)) {
+ tok = au_to_arg32(3, "new file gid", ar->ar_arg_gid);
+ kau_write(rec, tok);
+ }
+ UPATH1_VNODE1_TOKENS;
+ break;
+
+ case AUE_EXCHANGEDATA:
+ UPATH1_VNODE1_TOKENS;
+ UPATH2_TOKENS;
+ break;
+
+ case AUE_CLOSE:
+ if (ARG_IS_VALID(kar, ARG_FD)) {
+ tok = au_to_arg32(2, "fd", ar->ar_arg_fd);
+ kau_write(rec, tok);
+ }
+ UPATH1_VNODE1_TOKENS;
+ break;
+
+ case AUE_CORE:
+ if (ARG_IS_VALID(kar, ARG_SIGNUM)) {
+ tok = au_to_arg32(0, "signal", ar->ar_arg_signum);
+ kau_write(rec, tok);
+ }
+ UPATH1_VNODE1_TOKENS;
+ break;
+
+ case AUE_EXTATTRCTL:
+ UPATH1_VNODE1_TOKENS;
+ if (ARG_IS_VALID(kar, ARG_CMD)) {
+ tok = au_to_arg32(2, "cmd", ar->ar_arg_cmd);
+ kau_write(rec, tok);
+ }
+ /* extattrctl(2) filename parameter is in upath2/vnode2 */
+ UPATH2_TOKENS;
+ VNODE2_TOKENS;
+ EXTATTR_TOKENS;
+ break;
+
+ case AUE_EXTATTR_GET_FILE:
+ case AUE_EXTATTR_SET_FILE:
+ case AUE_EXTATTR_LIST_FILE:
+ case AUE_EXTATTR_DELETE_FILE:
+ case AUE_EXTATTR_GET_LINK:
+ case AUE_EXTATTR_SET_LINK:
+ case AUE_EXTATTR_LIST_LINK:
+ case AUE_EXTATTR_DELETE_LINK:
+ UPATH1_VNODE1_TOKENS;
+ EXTATTR_TOKENS;
+ break;
+
+ case AUE_EXTATTR_GET_FD:
+ case AUE_EXTATTR_SET_FD:
+ case AUE_EXTATTR_LIST_FD:
+ case AUE_EXTATTR_DELETE_FD:
+ if (ARG_IS_VALID(kar, ARG_FD)) {
+ tok = au_to_arg32(2, "fd", ar->ar_arg_fd);
+ kau_write(rec, tok);
+ }
+ EXTATTR_TOKENS;
+ break;
+
+ case AUE_FEXECVE:
+ if (ARG_IS_VALID(kar, ARG_FD)) {
+ tok = au_to_arg32(1, "fd", ar->ar_arg_fd);
+ kau_write(rec, tok);
+ }
+ /* FALLTHROUGH */
+
+ case AUE_EXECVE:
+ if (ARG_IS_VALID(kar, ARG_ARGV)) {
+ tok = au_to_exec_args(ar->ar_arg_argv,
+ ar->ar_arg_argc);
+ kau_write(rec, tok);
+ }
+ if (ARG_IS_VALID(kar, ARG_ENVV)) {
+ tok = au_to_exec_env(ar->ar_arg_envv,
+ ar->ar_arg_envc);
+ kau_write(rec, tok);
+ }
+ UPATH1_VNODE1_TOKENS;
+ break;
+
+ case AUE_FCHMOD:
+ if (ARG_IS_VALID(kar, ARG_MODE)) {
+ tok = au_to_arg32(2, "new file mode",
+ ar->ar_arg_mode);
+ kau_write(rec, tok);
+ }
+ FD_VNODE1_TOKENS;
+ break;
+
+ /*
+ * XXXRW: Some of these need to handle non-vnode cases as well.
+ */
+ case AUE_FCHDIR:
+ case AUE_FPATHCONF:
+ case AUE_FSTAT:
+ case AUE_FSTATFS:
+ case AUE_FSYNC:
+ case AUE_FTRUNCATE:
+ case AUE_FUTIMES:
+ case AUE_GETDIRENTRIES:
+ case AUE_GETDIRENTRIESATTR:
+ case AUE_POLL:
+ case AUE_READ:
+ case AUE_READV:
+ case AUE_WRITE:
+ case AUE_WRITEV:
+ FD_VNODE1_TOKENS;
+ break;
+
+ case AUE_FCHOWN:
+ if (ARG_IS_VALID(kar, ARG_UID)) {
+ tok = au_to_arg32(2, "new file uid", ar->ar_arg_uid);
+ kau_write(rec, tok);
+ }
+ if (ARG_IS_VALID(kar, ARG_GID)) {
+ tok = au_to_arg32(3, "new file gid", ar->ar_arg_gid);
+ kau_write(rec, tok);
+ }
+ FD_VNODE1_TOKENS;
+ break;
+
+ case AUE_FCNTL:
+ if (ar->ar_arg_cmd == F_GETLK || ar->ar_arg_cmd == F_SETLK ||
+ ar->ar_arg_cmd == F_SETLKW) {
+ if (ARG_IS_VALID(kar, ARG_CMD)) {
+ tok = au_to_arg32(2, "cmd", ar->ar_arg_cmd);
+ kau_write(rec, tok);
+ }
+ FD_VNODE1_TOKENS;
+ }
+ break;
+
+ case AUE_FCHFLAGS:
+ if (ARG_IS_VALID(kar, ARG_FFLAGS)) {
+ tok = au_to_arg32(2, "flags", ar->ar_arg_fflags);
+ kau_write(rec, tok);
+ }
+ FD_VNODE1_TOKENS;
+ break;
+
+ case AUE_FLOCK:
+ if (ARG_IS_VALID(kar, ARG_CMD)) {
+ tok = au_to_arg32(2, "operation", ar->ar_arg_cmd);
+ kau_write(rec, tok);
+ }
+ FD_VNODE1_TOKENS;
+ break;
+
+ case AUE_RFORK:
+ if (ARG_IS_VALID(kar, ARG_FFLAGS)) {
+ tok = au_to_arg32(1, "flags", ar->ar_arg_fflags);
+ kau_write(rec, tok);
+ }
+ /* FALLTHROUGH */
+
+ case AUE_FORK:
+ case AUE_VFORK:
+ if (ARG_IS_VALID(kar, ARG_PID)) {
+ tok = au_to_arg32(0, "child PID", ar->ar_arg_pid);
+ kau_write(rec, tok);
+ }
+ break;
+
+ case AUE_IOCTL:
+ if (ARG_IS_VALID(kar, ARG_CMD)) {
+ tok = au_to_arg32(2, "cmd", ar->ar_arg_cmd);
+ kau_write(rec, tok);
+ }
+ if (ARG_IS_VALID(kar, ARG_ADDR)) {
+ tok = au_to_arg32(1, "arg",
+ (u_int32_t)(uintptr_t)ar->ar_arg_addr);
+ kau_write(rec, tok);
+ }
+ if (ARG_IS_VALID(kar, ARG_VNODE1))
+ FD_VNODE1_TOKENS;
+ else {
+ if (ARG_IS_VALID(kar, ARG_SOCKINFO)) {
+ tok = kau_to_socket(&ar->ar_arg_sockinfo);
+ kau_write(rec, tok);
+ } else {
+ if (ARG_IS_VALID(kar, ARG_FD)) {
+ tok = au_to_arg32(1, "fd",
+ ar->ar_arg_fd);
+ kau_write(rec, tok);
+ }
+ }
+ }
+ break;
+
+ case AUE_KILL:
+ case AUE_KILLPG:
+ if (ARG_IS_VALID(kar, ARG_SIGNUM)) {
+ tok = au_to_arg32(2, "signal", ar->ar_arg_signum);
+ kau_write(rec, tok);
+ }
+ PROCESS_PID_TOKENS(1);
+ break;
+
+ case AUE_KTRACE:
+ if (ARG_IS_VALID(kar, ARG_CMD)) {
+ tok = au_to_arg32(2, "ops", ar->ar_arg_cmd);
+ kau_write(rec, tok);
+ }
+ if (ARG_IS_VALID(kar, ARG_VALUE)) {
+ tok = au_to_arg32(3, "trpoints", ar->ar_arg_value);
+ kau_write(rec, tok);
+ }
+ PROCESS_PID_TOKENS(4);
+ UPATH1_VNODE1_TOKENS;
+ break;
+
+ case AUE_LINK:
+ case AUE_RENAME:
+ UPATH1_VNODE1_TOKENS;
+ UPATH2_TOKENS;
+ break;
+
+ case AUE_LOADSHFILE:
+ if (ARG_IS_VALID(kar, ARG_ADDR)) {
+ tok = au_to_arg32(4, "base addr",
+ (u_int32_t)(uintptr_t)ar->ar_arg_addr);
+ kau_write(rec, tok);
+ }
+ UPATH1_VNODE1_TOKENS;
+ break;
+
+ case AUE_MKDIR:
+ if (ARG_IS_VALID(kar, ARG_MODE)) {
+ tok = au_to_arg32(2, "mode", ar->ar_arg_mode);
+ kau_write(rec, tok);
+ }
+ UPATH1_VNODE1_TOKENS;
+ break;
+
+ case AUE_MKNOD:
+ if (ARG_IS_VALID(kar, ARG_MODE)) {
+ tok = au_to_arg32(2, "mode", ar->ar_arg_mode);
+ kau_write(rec, tok);
+ }
+ if (ARG_IS_VALID(kar, ARG_DEV)) {
+ tok = au_to_arg32(3, "dev", ar->ar_arg_dev);
+ kau_write(rec, tok);
+ }
+ UPATH1_VNODE1_TOKENS;
+ break;
+
+ case AUE_MMAP:
+ case AUE_MUNMAP:
+ case AUE_MPROTECT:
+ case AUE_MLOCK:
+ case AUE_MUNLOCK:
+ case AUE_MINHERIT:
+ if (ARG_IS_VALID(kar, ARG_ADDR)) {
+ tok = au_to_arg32(1, "addr",
+ (u_int32_t)(uintptr_t)ar->ar_arg_addr);
+ kau_write(rec, tok);
+ }
+ if (ARG_IS_VALID(kar, ARG_LEN)) {
+ tok = au_to_arg32(2, "len", ar->ar_arg_len);
+ kau_write(rec, tok);
+ }
+ if (ar->ar_event == AUE_MMAP)
+ FD_VNODE1_TOKENS;
+ if (ar->ar_event == AUE_MPROTECT) {
+ if (ARG_IS_VALID(kar, ARG_VALUE)) {
+ tok = au_to_arg32(3, "protection",
+ ar->ar_arg_value);
+ kau_write(rec, tok);
+ }
+ }
+ if (ar->ar_event == AUE_MINHERIT) {
+ if (ARG_IS_VALID(kar, ARG_VALUE)) {
+ tok = au_to_arg32(3, "inherit",
+ ar->ar_arg_value);
+ kau_write(rec, tok);
+ }
+ }
+ break;
+
+ case AUE_MOUNT:
+ case AUE_NMOUNT:
+ /* XXX Need to handle NFS mounts */
+ if (ARG_IS_VALID(kar, ARG_FFLAGS)) {
+ tok = au_to_arg32(3, "flags", ar->ar_arg_fflags);
+ kau_write(rec, tok);
+ }
+ if (ARG_IS_VALID(kar, ARG_TEXT)) {
+ tok = au_to_text(ar->ar_arg_text);
+ kau_write(rec, tok);
+ }
+ /* FALLTHROUGH */
+
+ case AUE_UMOUNT:
+ UPATH1_VNODE1_TOKENS;
+ break;
+
+ case AUE_MSGCTL:
+ ar->ar_event = audit_msgctl_to_event(ar->ar_arg_svipc_cmd);
+ /* Fall through */
+
+ case AUE_MSGRCV:
+ case AUE_MSGSND:
+ tok = au_to_arg32(1, "msg ID", ar->ar_arg_svipc_id);
+ kau_write(rec, tok);
+ if (ar->ar_errno != EINVAL) {
+ tok = au_to_ipc(AT_IPC_MSG, ar->ar_arg_svipc_id);
+ kau_write(rec, tok);
+ }
+ break;
+
+ case AUE_MSGGET:
+ if (ar->ar_errno == 0) {
+ if (ARG_IS_VALID(kar, ARG_SVIPC_ID)) {
+ tok = au_to_ipc(AT_IPC_MSG,
+ ar->ar_arg_svipc_id);
+ kau_write(rec, tok);
+ }
+ }
+ break;
+
+ case AUE_RESETSHFILE:
+ if (ARG_IS_VALID(kar, ARG_ADDR)) {
+ tok = au_to_arg32(1, "base addr",
+ (u_int32_t)(uintptr_t)ar->ar_arg_addr);
+ kau_write(rec, tok);
+ }
+ break;
+
+ case AUE_OPEN_RC:
+ case AUE_OPEN_RTC:
+ case AUE_OPEN_RWC:
+ case AUE_OPEN_RWTC:
+ case AUE_OPEN_WC:
+ case AUE_OPEN_WTC:
+ case AUE_CREAT:
+ if (ARG_IS_VALID(kar, ARG_MODE)) {
+ tok = au_to_arg32(3, "mode", ar->ar_arg_mode);
+ kau_write(rec, tok);
+ }
+ /* FALLTHROUGH */
+
+ case AUE_OPEN_R:
+ case AUE_OPEN_RT:
+ case AUE_OPEN_RW:
+ case AUE_OPEN_RWT:
+ case AUE_OPEN_W:
+ case AUE_OPEN_WT:
+ if (ARG_IS_VALID(kar, ARG_FFLAGS)) {
+ tok = au_to_arg32(2, "flags", ar->ar_arg_fflags);
+ kau_write(rec, tok);
+ }
+ UPATH1_VNODE1_TOKENS;
+ break;
+
+ case AUE_PTRACE:
+ if (ARG_IS_VALID(kar, ARG_CMD)) {
+ tok = au_to_arg32(1, "request", ar->ar_arg_cmd);
+ kau_write(rec, tok);
+ }
+ if (ARG_IS_VALID(kar, ARG_ADDR)) {
+ tok = au_to_arg32(3, "addr",
+ (u_int32_t)(uintptr_t)ar->ar_arg_addr);
+ kau_write(rec, tok);
+ }
+ if (ARG_IS_VALID(kar, ARG_VALUE)) {
+ tok = au_to_arg32(4, "data", ar->ar_arg_value);
+ kau_write(rec, tok);
+ }
+ PROCESS_PID_TOKENS(2);
+ break;
+
+ case AUE_QUOTACTL:
+ if (ARG_IS_VALID(kar, ARG_CMD)) {
+ tok = au_to_arg32(2, "command", ar->ar_arg_cmd);
+ kau_write(rec, tok);
+ }
+ if (ARG_IS_VALID(kar, ARG_UID)) {
+ tok = au_to_arg32(3, "uid", ar->ar_arg_uid);
+ kau_write(rec, tok);
+ }
+ UPATH1_VNODE1_TOKENS;
+ break;
+
+ case AUE_REBOOT:
+ if (ARG_IS_VALID(kar, ARG_CMD)) {
+ tok = au_to_arg32(1, "howto", ar->ar_arg_cmd);
+ kau_write(rec, tok);
+ }
+ break;
+
+ case AUE_SEMCTL:
+ ar->ar_event = audit_semctl_to_event(ar->ar_arg_svipc_cmd);
+ /* Fall through */
+
+ case AUE_SEMOP:
+ if (ARG_IS_VALID(kar, ARG_SVIPC_ID)) {
+ tok = au_to_arg32(1, "sem ID", ar->ar_arg_svipc_id);
+ kau_write(rec, tok);
+ if (ar->ar_errno != EINVAL) {
+ tok = au_to_ipc(AT_IPC_SEM,
+ ar->ar_arg_svipc_id);
+ kau_write(rec, tok);
+ }
+ }
+ break;
+
+ case AUE_SEMGET:
+ if (ar->ar_errno == 0) {
+ if (ARG_IS_VALID(kar, ARG_SVIPC_ID)) {
+ tok = au_to_ipc(AT_IPC_SEM,
+ ar->ar_arg_svipc_id);
+ kau_write(rec, tok);
+ }
+ }
+ break;
+
+ case AUE_SETEGID:
+ if (ARG_IS_VALID(kar, ARG_EGID)) {
+ tok = au_to_arg32(1, "gid", ar->ar_arg_egid);
+ kau_write(rec, tok);
+ }
+ break;
+
+ case AUE_SETEUID:
+ if (ARG_IS_VALID(kar, ARG_EUID)) {
+ tok = au_to_arg32(1, "uid", ar->ar_arg_euid);
+ kau_write(rec, tok);
+ }
+ break;
+
+ case AUE_SETREGID:
+ if (ARG_IS_VALID(kar, ARG_RGID)) {
+ tok = au_to_arg32(1, "rgid", ar->ar_arg_rgid);
+ kau_write(rec, tok);
+ }
+ if (ARG_IS_VALID(kar, ARG_EGID)) {
+ tok = au_to_arg32(2, "egid", ar->ar_arg_egid);
+ kau_write(rec, tok);
+ }
+ break;
+
+ case AUE_SETREUID:
+ if (ARG_IS_VALID(kar, ARG_RUID)) {
+ tok = au_to_arg32(1, "ruid", ar->ar_arg_ruid);
+ kau_write(rec, tok);
+ }
+ if (ARG_IS_VALID(kar, ARG_EUID)) {
+ tok = au_to_arg32(2, "euid", ar->ar_arg_euid);
+ kau_write(rec, tok);
+ }
+ break;
+
+ case AUE_SETRESGID:
+ if (ARG_IS_VALID(kar, ARG_RGID)) {
+ tok = au_to_arg32(1, "rgid", ar->ar_arg_rgid);
+ kau_write(rec, tok);
+ }
+ if (ARG_IS_VALID(kar, ARG_EGID)) {
+ tok = au_to_arg32(2, "egid", ar->ar_arg_egid);
+ kau_write(rec, tok);
+ }
+ if (ARG_IS_VALID(kar, ARG_SGID)) {
+ tok = au_to_arg32(3, "sgid", ar->ar_arg_sgid);
+ kau_write(rec, tok);
+ }
+ break;
+
+ case AUE_SETRESUID:
+ if (ARG_IS_VALID(kar, ARG_RUID)) {
+ tok = au_to_arg32(1, "ruid", ar->ar_arg_ruid);
+ kau_write(rec, tok);
+ }
+ if (ARG_IS_VALID(kar, ARG_EUID)) {
+ tok = au_to_arg32(2, "euid", ar->ar_arg_euid);
+ kau_write(rec, tok);
+ }
+ if (ARG_IS_VALID(kar, ARG_SUID)) {
+ tok = au_to_arg32(3, "suid", ar->ar_arg_suid);
+ kau_write(rec, tok);
+ }
+ break;
+
+ case AUE_SETGID:
+ if (ARG_IS_VALID(kar, ARG_GID)) {
+ tok = au_to_arg32(1, "gid", ar->ar_arg_gid);
+ kau_write(rec, tok);
+ }
+ break;
+
+ case AUE_SETUID:
+ if (ARG_IS_VALID(kar, ARG_UID)) {
+ tok = au_to_arg32(1, "uid", ar->ar_arg_uid);
+ kau_write(rec, tok);
+ }
+ break;
+
+ case AUE_SETGROUPS:
+ if (ARG_IS_VALID(kar, ARG_GROUPSET)) {
+ for(ctr = 0; ctr < ar->ar_arg_groups.gidset_size; ctr++)
+ {
+ tok = au_to_arg32(1, "setgroups",
+ ar->ar_arg_groups.gidset[ctr]);
+ kau_write(rec, tok);
+ }
+ }
+ break;
+
+ case AUE_SETLOGIN:
+ if (ARG_IS_VALID(kar, ARG_TEXT)) {
+ tok = au_to_text(ar->ar_arg_text);
+ kau_write(rec, tok);
+ }
+ break;
+
+ case AUE_SETPRIORITY:
+ if (ARG_IS_VALID(kar, ARG_CMD)) {
+ tok = au_to_arg32(1, "which", ar->ar_arg_cmd);
+ kau_write(rec, tok);
+ }
+ if (ARG_IS_VALID(kar, ARG_UID)) {
+ tok = au_to_arg32(2, "who", ar->ar_arg_uid);
+ kau_write(rec, tok);
+ }
+ if (ARG_IS_VALID(kar, ARG_VALUE)) {
+ tok = au_to_arg32(2, "priority", ar->ar_arg_value);
+ kau_write(rec, tok);
+ }
+ break;
+
+ case AUE_SETPRIVEXEC:
+ if (ARG_IS_VALID(kar, ARG_VALUE)) {
+ tok = au_to_arg32(1, "flag", ar->ar_arg_value);
+ kau_write(rec, tok);
+ }
+ break;
+
+ /* AUE_SHMAT, AUE_SHMCTL, AUE_SHMDT and AUE_SHMGET are SysV IPC */
+ case AUE_SHMAT:
+ if (ARG_IS_VALID(kar, ARG_SVIPC_ID)) {
+ tok = au_to_arg32(1, "shmid", ar->ar_arg_svipc_id);
+ kau_write(rec, tok);
+ /* XXXAUDIT: Does having the ipc token make sense? */
+ tok = au_to_ipc(AT_IPC_SHM, ar->ar_arg_svipc_id);
+ kau_write(rec, tok);
+ }
+ if (ARG_IS_VALID(kar, ARG_SVIPC_ADDR)) {
+ tok = au_to_arg32(2, "shmaddr",
+ (int)(uintptr_t)ar->ar_arg_svipc_addr);
+ kau_write(rec, tok);
+ }
+ if (ARG_IS_VALID(kar, ARG_SVIPC_PERM)) {
+ tok = au_to_ipc_perm(&ar->ar_arg_svipc_perm);
+ kau_write(rec, tok);
+ }
+ break;
+
+ case AUE_SHMCTL:
+ if (ARG_IS_VALID(kar, ARG_SVIPC_ID)) {
+ tok = au_to_arg32(1, "shmid", ar->ar_arg_svipc_id);
+ kau_write(rec, tok);
+ /* XXXAUDIT: Does having the ipc token make sense? */
+ tok = au_to_ipc(AT_IPC_SHM, ar->ar_arg_svipc_id);
+ kau_write(rec, tok);
+ }
+ switch (ar->ar_arg_svipc_cmd) {
+ case IPC_STAT:
+ ar->ar_event = AUE_SHMCTL_STAT;
+ break;
+ case IPC_RMID:
+ ar->ar_event = AUE_SHMCTL_RMID;
+ break;
+ case IPC_SET:
+ ar->ar_event = AUE_SHMCTL_SET;
+ if (ARG_IS_VALID(kar, ARG_SVIPC_PERM)) {
+ tok = au_to_ipc_perm(&ar->ar_arg_svipc_perm);
+ kau_write(rec, tok);
+ }
+ break;
+ default:
+ break; /* We will audit a bad command */
+ }
+ break;
+
+ case AUE_SHMDT:
+ if (ARG_IS_VALID(kar, ARG_SVIPC_ADDR)) {
+ tok = au_to_arg32(1, "shmaddr",
+ (int)(uintptr_t)ar->ar_arg_svipc_addr);
+ kau_write(rec, tok);
+ }
+ break;
+
+ case AUE_SHMGET:
+ /* This is unusual; the return value is in an argument token */
+ if (ARG_IS_VALID(kar, ARG_SVIPC_ID)) {
+ tok = au_to_arg32(0, "shmid", ar->ar_arg_svipc_id);
+ kau_write(rec, tok);
+ tok = au_to_ipc(AT_IPC_SHM, ar->ar_arg_svipc_id);
+ kau_write(rec, tok);
+ }
+ if (ARG_IS_VALID(kar, ARG_SVIPC_PERM)) {
+ tok = au_to_ipc_perm(&ar->ar_arg_svipc_perm);
+ kau_write(rec, tok);
+ }
+ break;
+
+ /* AUE_SHMOPEN, AUE_SHMUNLINK, AUE_SEMOPEN, AUE_SEMCLOSE
+ * and AUE_SEMUNLINK are Posix IPC */
+ case AUE_SHMOPEN:
+ if (ARG_IS_VALID(kar, ARG_SVIPC_ADDR)) {
+ tok = au_to_arg32(2, "flags", ar->ar_arg_fflags);
+ kau_write(rec, tok);
+ }
+ if (ARG_IS_VALID(kar, ARG_MODE)) {
+ tok = au_to_arg32(3, "mode", ar->ar_arg_mode);
+ kau_write(rec, tok);
+ }
+ /* FALLTHROUGH */
+
+ case AUE_SHMUNLINK:
+ if (ARG_IS_VALID(kar, ARG_TEXT)) {
+ tok = au_to_text(ar->ar_arg_text);
+ kau_write(rec, tok);
+ }
+ if (ARG_IS_VALID(kar, ARG_POSIX_IPC_PERM)) {
+ struct ipc_perm perm;
+
+ perm.uid = ar->ar_arg_pipc_perm.pipc_uid;
+ perm.gid = ar->ar_arg_pipc_perm.pipc_gid;
+ perm.cuid = ar->ar_arg_pipc_perm.pipc_uid;
+ perm.cgid = ar->ar_arg_pipc_perm.pipc_gid;
+ perm.mode = ar->ar_arg_pipc_perm.pipc_mode;
+ perm.seq = 0;
+ perm.key = 0;
+ tok = au_to_ipc_perm(&perm);
+ kau_write(rec, tok);
+ }
+ break;
+
+ case AUE_SEMOPEN:
+ if (ARG_IS_VALID(kar, ARG_FFLAGS)) {
+ tok = au_to_arg32(2, "flags", ar->ar_arg_fflags);
+ kau_write(rec, tok);
+ }
+ if (ARG_IS_VALID(kar, ARG_MODE)) {
+ tok = au_to_arg32(3, "mode", ar->ar_arg_mode);
+ kau_write(rec, tok);
+ }
+ if (ARG_IS_VALID(kar, ARG_VALUE)) {
+ tok = au_to_arg32(4, "value", ar->ar_arg_value);
+ kau_write(rec, tok);
+ }
+ /* FALLTHROUGH */
+
+ case AUE_SEMUNLINK:
+ if (ARG_IS_VALID(kar, ARG_TEXT)) {
+ tok = au_to_text(ar->ar_arg_text);
+ kau_write(rec, tok);
+ }
+ if (ARG_IS_VALID(kar, ARG_POSIX_IPC_PERM)) {
+ struct ipc_perm perm;
+
+ perm.uid = ar->ar_arg_pipc_perm.pipc_uid;
+ perm.gid = ar->ar_arg_pipc_perm.pipc_gid;
+ perm.cuid = ar->ar_arg_pipc_perm.pipc_uid;
+ perm.cgid = ar->ar_arg_pipc_perm.pipc_gid;
+ perm.mode = ar->ar_arg_pipc_perm.pipc_mode;
+ perm.seq = 0;
+ perm.key = 0;
+ tok = au_to_ipc_perm(&perm);
+ kau_write(rec, tok);
+ }
+ break;
+
+ case AUE_SEMCLOSE:
+ if (ARG_IS_VALID(kar, ARG_FD)) {
+ tok = au_to_arg32(1, "sem", ar->ar_arg_fd);
+ kau_write(rec, tok);
+ }
+ break;
+
+ case AUE_SYMLINK:
+ if (ARG_IS_VALID(kar, ARG_TEXT)) {
+ tok = au_to_text(ar->ar_arg_text);
+ kau_write(rec, tok);
+ }
+ UPATH1_VNODE1_TOKENS;
+ break;
+
+ case AUE_SYSCTL:
+ case AUE_SYSCTL_NONADMIN:
+ if (ARG_IS_VALID(kar, ARG_CTLNAME | ARG_LEN)) {
+ for (ctr = 0; ctr < ar->ar_arg_len; ctr++) {
+ tok = au_to_arg32(1, "name",
+ ar->ar_arg_ctlname[ctr]);
+ kau_write(rec, tok);
+ }
+ }
+ if (ARG_IS_VALID(kar, ARG_VALUE)) {
+ tok = au_to_arg32(5, "newval", ar->ar_arg_value);
+ kau_write(rec, tok);
+ }
+ if (ARG_IS_VALID(kar, ARG_TEXT)) {
+ tok = au_to_text(ar->ar_arg_text);
+ kau_write(rec, tok);
+ }
+ break;
+
+ case AUE_UMASK:
+ if (ARG_IS_VALID(kar, ARG_MASK)) {
+ tok = au_to_arg32(1, "new mask", ar->ar_arg_mask);
+ kau_write(rec, tok);
+ }
+ tok = au_to_arg32(0, "prev mask", ar->ar_retval);
+ kau_write(rec, tok);
+ break;
+
+ case AUE_WAIT4:
+ if (ARG_IS_VALID(kar, ARG_PID)) {
+ tok = au_to_arg32(0, "pid", ar->ar_arg_pid);
+ kau_write(rec, tok);
+ }
+ break;
+
+ case AUE_NULL:
+ default:
+ printf("BSM conversion requested for unknown event %d\n",
+ ar->ar_event);
+
+ /*
+ * Write the subject token so it is properly freed here.
+ */
+ kau_write(rec, subj_tok);
+ kau_free(rec);
+ return (BSM_NOAUDIT);
+ }
+
+ kau_write(rec, subj_tok);
+ tok = au_to_return32((char)ar->ar_errno, ar->ar_retval);
+ kau_write(rec, tok); /* Every record gets a return token */
+
+ kau_close(rec, &ar->ar_endtime, ar->ar_event);
+
+ *pau = rec;
+ return (BSM_SUCCESS);
+}
+
+/*
+ * Verify that a record is a valid BSM record. This verification is simple
+ * now, but may be expanded on sometime in the future. Return 1 if the
+ * record is good, 0 otherwise.
+ */
+int
+bsm_rec_verify(void *rec)
+{
+ char c = *(char *)rec;
+
+ /*
+ * Check the token ID of the first token; it has to be a header
+ * token.
+ *
+ * XXXAUDIT There needs to be a token structure to map a token.
+ * XXXAUDIT 'Shouldn't be simply looking at the first char.
+ */
+ if ((c != AUT_HEADER32) && (c != AUT_HEADER32_EX) &&
+ (c != AUT_HEADER64) && (c != AUT_HEADER64_EX))
+ return (0);
+ return (1);
+}
diff --git a/sys/security/audit/audit_bsm_errno.c b/sys/security/audit/audit_bsm_errno.c
new file mode 100644
index 0000000..7586213
--- /dev/null
+++ b/sys/security/audit/audit_bsm_errno.c
@@ -0,0 +1,642 @@
+/*-
+ * Copyright (c) 2008 Apple Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * P4: //depot/projects/trustedbsd/openbsm/libbsm/bsm_errno.c#12
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+
+#include <bsm/audit_errno.h>
+#include <bsm/libbsm.h>
+
+#include <sys/errno.h>
+
+/*
+ * Different operating systems use different numeric constants for different
+ * error numbers, and sometimes error numbers don't exist in more than one
+ * operating system. These routines convert between BSM and local error
+ * number spaces, subject to the above realities. BSM error numbers are
+ * stored in a single 8-bit character, so don't have a byte order.
+ */
+
+struct bsm_errors {
+ int be_bsm_error;
+ int be_os_error;
+ const char *be_strerror;
+};
+
+#define ERRNO_NO_LOCAL_MAPPING -600
+
+/*
+ * Mapping table -- please maintain in numeric sorted order with respect to
+ * the BSM constant. Today we do a linear lookup, but could switch to a
+ * binary search if it makes sense. We only ifdef errors that aren't
+ * generally available, but it does make the table a lot more ugly.
+ *
+ * XXXRW: It would be nice to have a similar ordered table mapping to BSM
+ * constant from local constant, but the order of local constants varies by
+ * OS. Really we need to build that table at compile-time but don't do that
+ * yet.
+ *
+ * XXXRW: We currently embed English-language error strings here, but should
+ * support catalogues; these are only used if the OS doesn't have an error
+ * string using strerror(3).
+ */
+static const struct bsm_errors bsm_errors[] = {
+ { BSM_ESUCCESS, 0, "Success" },
+ { BSM_EPERM, EPERM, "Operation not permitted" },
+ { BSM_ENOENT, ENOENT, "No such file or directory" },
+ { BSM_ESRCH, ESRCH, "No such process" },
+ { BSM_EINTR, EINTR, "Interrupted system call" },
+ { BSM_EIO, EIO, "Input/output error" },
+ { BSM_ENXIO, ENXIO, "Device not configured" },
+ { BSM_E2BIG, E2BIG, "Argument list too long" },
+ { BSM_ENOEXEC, ENOEXEC, "Exec format error" },
+ { BSM_EBADF, EBADF, "BAd file descriptor" },
+ { BSM_ECHILD, ECHILD, "No child processes" },
+ { BSM_EAGAIN, EAGAIN, "Resource temporarily unavailable" },
+ { BSM_ENOMEM, ENOMEM, "Cannot allocate memory" },
+ { BSM_EACCES, EACCES, "Permission denied" },
+ { BSM_EFAULT, EFAULT, "Bad address" },
+ { BSM_ENOTBLK, ENOTBLK, "Block device required" },
+ { BSM_EBUSY, EBUSY, "Device busy" },
+ { BSM_EEXIST, EEXIST, "File exists" },
+ { BSM_EXDEV, EXDEV, "Cross-device link" },
+ { BSM_ENODEV, ENODEV, "Operation not supported by device" },
+ { BSM_ENOTDIR, ENOTDIR, "Not a directory" },
+ { BSM_EISDIR, EISDIR, "Is a directory" },
+ { BSM_EINVAL, EINVAL, "Invalid argument" },
+ { BSM_ENFILE, ENFILE, "Too many open files in system" },
+ { BSM_EMFILE, EMFILE, "Too many open files" },
+ { BSM_ENOTTY, ENOTTY, "Inappropriate ioctl for device" },
+ { BSM_ETXTBSY, ETXTBSY, "Text file busy" },
+ { BSM_EFBIG, EFBIG, "File too large" },
+ { BSM_ENOSPC, ENOSPC, "No space left on device" },
+ { BSM_ESPIPE, ESPIPE, "Illegal seek" },
+ { BSM_EROFS, EROFS, "Read-only file system" },
+ { BSM_EMLINK, EMLINK, "Too many links" },
+ { BSM_EPIPE, EPIPE, "Broken pipe" },
+ { BSM_EDOM, EDOM, "Numerical argument out of domain" },
+ { BSM_ERANGE, ERANGE, "Result too large" },
+ { BSM_ENOMSG, ENOMSG, "No message of desired type" },
+ { BSM_EIDRM, EIDRM, "Identifier removed" },
+ { BSM_ECHRNG,
+#ifdef ECHRNG
+ ECHRNG,
+#else
+ ERRNO_NO_LOCAL_MAPPING,
+#endif
+ "Channel number out of range" },
+ { BSM_EL2NSYNC,
+#ifdef EL2NSYNC
+ EL2NSYNC,
+#else
+ ERRNO_NO_LOCAL_MAPPING,
+#endif
+ "Level 2 not synchronized" },
+ { BSM_EL3HLT,
+#ifdef EL3HLT
+ EL3HLT,
+#else
+ ERRNO_NO_LOCAL_MAPPING,
+#endif
+ "Level 3 halted" },
+ { BSM_EL3RST,
+#ifdef EL3RST
+ EL3RST,
+#else
+ ERRNO_NO_LOCAL_MAPPING,
+#endif
+ "Level 3 reset" },
+ { BSM_ELNRNG,
+#ifdef ELNRNG
+ ELNRNG,
+#else
+ ERRNO_NO_LOCAL_MAPPING,
+#endif
+ "Link number out of range" },
+ { BSM_EUNATCH,
+#ifdef EUNATCH
+ EUNATCH,
+#else
+ ERRNO_NO_LOCAL_MAPPING,
+#endif
+ "Protocol driver not attached" },
+ { BSM_ENOCSI,
+#ifdef ENOCSI
+ ENOCSI,
+#else
+ ERRNO_NO_LOCAL_MAPPING,
+#endif
+ "No CSI structure available" },
+ { BSM_EL2HLT,
+#ifdef EL2HLT
+ EL2HLT,
+#else
+ ERRNO_NO_LOCAL_MAPPING,
+#endif
+ "Level 2 halted" },
+ { BSM_EDEADLK, EDEADLK, "Resource deadlock avoided" },
+ { BSM_ENOLCK, ENOLCK, "No locks available" },
+ { BSM_ECANCELED, ECANCELED, "Operation canceled" },
+ { BSM_ENOTSUP, ENOTSUP, "Operation not supported" },
+ { BSM_EDQUOT, EDQUOT, "Disc quota exceeded" },
+ { BSM_EBADE,
+#ifdef EBADE
+ EBADE,
+#else
+ ERRNO_NO_LOCAL_MAPPING,
+#endif
+ "Invalid exchange" },
+ { BSM_EBADR,
+#ifdef EBADR
+ EBADR,
+#else
+ ERRNO_NO_LOCAL_MAPPING,
+#endif
+ "Invalid request descriptor" },
+ { BSM_EXFULL,
+#ifdef EXFULL
+ EXFULL,
+#else
+ ERRNO_NO_LOCAL_MAPPING,
+#endif
+ "Exchange full" },
+ { BSM_ENOANO,
+#ifdef ENOANO
+ ENOANO,
+#else
+ ERRNO_NO_LOCAL_MAPPING,
+#endif
+ "No anode" },
+ { BSM_EBADRQC,
+#ifdef EBADRQC
+ EBADRQC,
+#else
+ ERRNO_NO_LOCAL_MAPPING,
+#endif
+ "Invalid request descriptor" },
+ { BSM_EBADSLT,
+#ifdef EBADSLT
+ EBADSLT,
+#else
+ ERRNO_NO_LOCAL_MAPPING,
+#endif
+ "Invalid slot" },
+ { BSM_EDEADLOCK,
+#ifdef EDEADLOCK
+ EDEADLOCK,
+#else
+ ERRNO_NO_LOCAL_MAPPING,
+#endif
+ "Resource deadlock avoided" },
+ { BSM_EBFONT,
+#ifdef EBFONT
+ EBFONT,
+#else
+ ERRNO_NO_LOCAL_MAPPING,
+#endif
+ "Bad font file format" },
+ { BSM_EOWNERDEAD,
+#ifdef EOWNERDEAD
+ EOWNERDEAD,
+#else
+ ERRNO_NO_LOCAL_MAPPING,
+#endif
+ "Process died with the lock" },
+ { BSM_ENOTRECOVERABLE,
+#ifdef ENOTRECOVERABLE
+ ENOTRECOVERABLE,
+#else
+ ERRNO_NO_LOCAL_MAPPING,
+#endif
+ "Lock is not recoverable" },
+ { BSM_ENOSTR,
+#ifdef ENOSTR
+ ENOSTR,
+#else
+ ERRNO_NO_LOCAL_MAPPING,
+#endif
+ "Device not a stream" },
+ { BSM_ENONET,
+#ifdef ENONET
+ ENONET,
+#else
+ ERRNO_NO_LOCAL_MAPPING,
+#endif
+ "Machine is not on the network" },
+ { BSM_ENOPKG,
+#ifdef ENOPKG
+ ENOPKG,
+#else
+ ERRNO_NO_LOCAL_MAPPING,
+#endif
+ "Package not installed" },
+ { BSM_EREMOTE, EREMOTE, "Too many levels of remote in path" },
+ { BSM_ENOLINK,
+#ifdef ENOLINK
+ ENOLINK,
+#else
+ ERRNO_NO_LOCAL_MAPPING,
+#endif
+ "Link has been severed" },
+ { BSM_EADV,
+#ifdef EADV
+ EADV,
+#else
+ ERRNO_NO_LOCAL_MAPPING,
+#endif
+ "Advertise error" },
+ { BSM_ESRMNT,
+#ifdef ESRMNT
+ ESRMNT,
+#else
+ ERRNO_NO_LOCAL_MAPPING,
+#endif
+ "srmount error" },
+ { BSM_ECOMM,
+#ifdef ECOMM
+ ECOMM,
+#else
+ ERRNO_NO_LOCAL_MAPPING,
+#endif
+ "Communication error on send" },
+ { BSM_EPROTO,
+#ifdef EPROTO
+ EPROTO,
+#else
+ ERRNO_NO_LOCAL_MAPPING,
+#endif
+ "Protocol error" },
+ { BSM_ELOCKUNMAPPED,
+#ifdef ELOCKUNMAPPED
+ ELOCKUNMAPPED,
+#else
+ ERRNO_NO_LOCAL_MAPPING,
+#endif
+ "Locked lock was unmapped" },
+ { BSM_ENOTACTIVE,
+#ifdef ENOTACTIVE
+ ENOTACTIVE,
+#else
+ ERRNO_NO_LOCAL_MAPPING,
+#endif
+ "Facility is not active" },
+ { BSM_EMULTIHOP,
+#ifdef EMULTIHOP
+ EMULTIHOP,
+#else
+ ERRNO_NO_LOCAL_MAPPING,
+#endif
+ "Multihop attempted" },
+ { BSM_EBADMSG,
+#ifdef EBADMSG
+ EBADMSG,
+#else
+ ERRNO_NO_LOCAL_MAPPING,
+#endif
+ "Bad message" },
+ { BSM_ENAMETOOLONG, ENAMETOOLONG, "File name too long" },
+ { BSM_EOVERFLOW, EOVERFLOW, "Value too large to be stored in data type" },
+ { BSM_ENOTUNIQ,
+#ifdef ENOTUNIQ
+ ENOTUNIQ,
+#else
+ ERRNO_NO_LOCAL_MAPPING,
+#endif
+ "Given log name not unique" },
+ { BSM_EBADFD,
+#ifdef EBADFD
+ EBADFD,
+#else
+ ERRNO_NO_LOCAL_MAPPING,
+#endif
+ "Given f.d. invalid for this operation" },
+ { BSM_EREMCHG,
+#ifdef EREMCHG
+ EREMCHG,
+#else
+ ERRNO_NO_LOCAL_MAPPING,
+#endif
+ "Remote address changed" },
+ { BSM_ELIBACC,
+#ifdef ELIBACC
+ ELIBACC,
+#else
+ ERRNO_NO_LOCAL_MAPPING,
+#endif
+ "Can't access a needed shared lib" },
+ { BSM_ELIBBAD,
+#ifdef ELIBBAD
+ ELIBBAD,
+#else
+ ERRNO_NO_LOCAL_MAPPING,
+#endif
+ "Accessing a corrupted shared lib" },
+ { BSM_ELIBSCN,
+#ifdef ELIBSCN
+ ELIBSCN,
+#else
+ ERRNO_NO_LOCAL_MAPPING,
+#endif
+ ".lib section in a.out corrupted" },
+ { BSM_ELIBMAX,
+#ifdef ELIBMAX
+ ELIBMAX,
+#else
+ ERRNO_NO_LOCAL_MAPPING,
+#endif
+ "Attempting to link in too many libs" },
+ { BSM_ELIBEXEC,
+#ifdef ELIBEXEC
+ ELIBEXEC,
+#else
+ ERRNO_NO_LOCAL_MAPPING,
+#endif
+ "Attempting to exec a shared library" },
+ { BSM_EILSEQ, EILSEQ, "Illegal byte sequence" },
+ { BSM_ENOSYS, ENOSYS, "Function not implemented" },
+ { BSM_ELOOP, ELOOP, "Too many levels of symbolic links" },
+ { BSM_ERESTART,
+#ifdef ERESTART
+ ERESTART,
+#else
+ ERRNO_NO_LOCAL_MAPPING,
+#endif
+ "Restart syscall" },
+ { BSM_ESTRPIPE,
+#ifdef ESTRPIPE
+ ESTRPIPE,
+#else
+ ERRNO_NO_LOCAL_MAPPING,
+#endif
+ "If pipe/FIFO, don't sleep in stream head" },
+ { BSM_ENOTEMPTY, ENOTEMPTY, "Directory not empty" },
+ { BSM_EUSERS, EUSERS, "Too many users" },
+ { BSM_ENOTSOCK, ENOTSOCK, "Socket operation on non-socket" },
+ { BSM_EDESTADDRREQ, EDESTADDRREQ, "Destination address required" },
+ { BSM_EMSGSIZE, EMSGSIZE, "Message too long" },
+ { BSM_EPROTOTYPE, EPROTOTYPE, "Protocol wrong type for socket" },
+ { BSM_ENOPROTOOPT, ENOPROTOOPT, "Protocol not available" },
+ { BSM_EPROTONOSUPPORT, EPROTONOSUPPORT, "Protocol not supported" },
+ { BSM_ESOCKTNOSUPPORT, ESOCKTNOSUPPORT, "Socket type not supported" },
+ { BSM_EOPNOTSUPP, EOPNOTSUPP, "Operation not supported" },
+ { BSM_EPFNOSUPPORT, EPFNOSUPPORT, "Protocol family not supported" },
+ { BSM_EAFNOSUPPORT, EAFNOSUPPORT, "Address family not supported by protocol family" },
+ { BSM_EADDRINUSE, EADDRINUSE, "Address already in use" },
+ { BSM_EADDRNOTAVAIL, EADDRNOTAVAIL, "Can't assign requested address" },
+ { BSM_ENETDOWN, ENETDOWN, "Network is down" },
+ { BSM_ENETRESET, ENETRESET, "Network dropped connection on reset" },
+ { BSM_ECONNABORTED, ECONNABORTED, "Software caused connection abort" },
+ { BSM_ECONNRESET, ECONNRESET, "Connection reset by peer" },
+ { BSM_ENOBUFS, ENOBUFS, "No buffer space available" },
+ { BSM_EISCONN, EISCONN, "Socket is already connected" },
+ { BSM_ENOTCONN, ENOTCONN, "Socket is not connected" },
+ { BSM_ESHUTDOWN, ESHUTDOWN, "Can't send after socket shutdown" },
+ { BSM_ETOOMANYREFS, ETOOMANYREFS, "Too many references: can't splice" },
+ { BSM_ETIMEDOUT, ETIMEDOUT, "Operation timed out" },
+ { BSM_ECONNREFUSED, ECONNREFUSED, "Connection refused" },
+ { BSM_EHOSTDOWN, EHOSTDOWN, "Host is down" },
+ { BSM_EHOSTUNREACH, EHOSTUNREACH, "No route to host" },
+ { BSM_EALREADY, EALREADY, "Operation already in progress" },
+ { BSM_EINPROGRESS, EINPROGRESS, "Operation now in progress" },
+ { BSM_ESTALE, ESTALE, "Stale NFS file handle" },
+ { BSM_EPWROFF,
+#ifdef EPWROFF
+ EPWROFF,
+#else
+ ERRNO_NO_LOCAL_MAPPING,
+#endif
+ "Device power is off" },
+ { BSM_EDEVERR,
+#ifdef EDEVERR
+ EDEVERR,
+#else
+ ERRNO_NO_LOCAL_MAPPING,
+#endif
+ "Device error" },
+ { BSM_EBADEXEC,
+#ifdef EBADEXEC
+ EBADEXEC,
+#else
+ ERRNO_NO_LOCAL_MAPPING,
+#endif
+ "Bad executable" },
+ { BSM_EBADARCH,
+#ifdef EBADARCH
+ EBADARCH,
+#else
+ ERRNO_NO_LOCAL_MAPPING,
+#endif
+ "Bad CPU type in executable" },
+ { BSM_ESHLIBVERS,
+#ifdef ESHLIBVERS
+ ESHLIBVERS,
+#else
+ ERRNO_NO_LOCAL_MAPPING,
+#endif
+ "Shared library version mismatch" },
+ { BSM_EBADMACHO,
+#ifdef EBADMACHO
+ EBADMACHO,
+#else
+ ERRNO_NO_LOCAL_MAPPING,
+#endif
+ "Malfored Macho file" },
+ { BSM_EPOLICY,
+#ifdef EPOLICY
+ EPOLICY,
+#else
+ ERRNO_NO_LOCAL_MAPPING,
+#endif
+ "Operation failed by policy" },
+ { BSM_EDOTDOT,
+#ifdef EDOTDOT
+ EDOTDOT,
+#else
+ ERRNO_NO_LOCAL_MAPPING,
+#endif
+ "RFS specific error" },
+ { BSM_EUCLEAN,
+#ifdef EUCLEAN
+ EUCLEAN,
+#else
+ ERRNO_NO_LOCAL_MAPPING,
+#endif
+ "Structure needs cleaning" },
+ { BSM_ENOTNAM,
+#ifdef ENOTNAM
+ ENOTNAM,
+#else
+ ERRNO_NO_LOCAL_MAPPING,
+#endif
+ "Not a XENIX named type file" },
+ { BSM_ENAVAIL,
+#ifdef ENAVAIL
+ ENAVAIL,
+#else
+ ERRNO_NO_LOCAL_MAPPING,
+#endif
+ "No XENIX semaphores available" },
+ { BSM_EISNAM,
+#ifdef EISNAM
+ EISNAM,
+#else
+ ERRNO_NO_LOCAL_MAPPING,
+#endif
+ "Is a named type file" },
+ { BSM_EREMOTEIO,
+#ifdef EREMOTEIO
+ EREMOTEIO,
+#else
+ ERRNO_NO_LOCAL_MAPPING,
+#endif
+ "Remote I/O error" },
+ { BSM_ENOMEDIUM,
+#ifdef ENOMEDIUM
+ ENOMEDIUM,
+#else
+ ERRNO_NO_LOCAL_MAPPING,
+#endif
+ "No medium found" },
+ { BSM_EMEDIUMTYPE,
+#ifdef EMEDIUMTYPE
+ EMEDIUMTYPE,
+#else
+ ERRNO_NO_LOCAL_MAPPING,
+#endif
+ "Wrong medium type" },
+ { BSM_ENOKEY,
+#ifdef ENOKEY
+ ENOKEY,
+#else
+ ERRNO_NO_LOCAL_MAPPING,
+#endif
+ "Required key not available" },
+ { BSM_EKEYEXPIRED,
+#ifdef EKEEXPIRED
+ EKEYEXPIRED,
+#else
+ ERRNO_NO_LOCAL_MAPPING,
+#endif
+ "Key has expired" },
+ { BSM_EKEYREVOKED,
+#ifdef EKEYREVOKED
+ EKEYREVOKED,
+#else
+ ERRNO_NO_LOCAL_MAPPING,
+#endif
+ "Key has been revoked" },
+ { BSM_EKEYREJECTED,
+#ifdef EKEREJECTED
+ EKEYREJECTED,
+#else
+ ERRNO_NO_LOCAL_MAPPING,
+#endif
+ "Key was rejected by service" },
+};
+static const int bsm_errors_count = sizeof(bsm_errors) / sizeof(bsm_errors[0]);
+
+static const struct bsm_errors *
+au_bsm_error_lookup_errno(int error)
+{
+ int i;
+
+ if (error == ERRNO_NO_LOCAL_MAPPING)
+ return (NULL);
+ for (i = 0; i < bsm_errors_count; i++) {
+ if (bsm_errors[i].be_os_error == error)
+ return (&bsm_errors[i]);
+ }
+ return (NULL);
+}
+
+static const struct bsm_errors *
+au_bsm_error_lookup_bsm(u_char bsm_error)
+{
+ int i;
+
+ for (i = 0; i < bsm_errors_count; i++) {
+ if (bsm_errors[i].be_bsm_error == bsm_error)
+ return (&bsm_errors[i]);
+ }
+ return (NULL);
+}
+
+/*
+ * Converstion from a BSM error to a local error number may fail if either
+ * OpenBSM doesn't recognize the error on the wire, or because there is no
+ * appropriate local mapping. However, we don't allow conversion to BSM to
+ * fail, we just convert to BSM_UKNOWNERR.
+ */
+int
+au_bsm_to_errno(u_char bsm_error, int *errorp)
+{
+ const struct bsm_errors *bsme;
+
+ bsme = au_bsm_error_lookup_bsm(bsm_error);
+ if (bsme == NULL || bsme->be_os_error == ERRNO_NO_LOCAL_MAPPING)
+ return (-1);
+ *errorp = bsme->be_os_error;
+ return (0);
+}
+
+u_char
+au_errno_to_bsm(int error)
+{
+ const struct bsm_errors *bsme;
+
+ /*
+ * We should never be passed this libbsm-internal constant, and
+ * because it is ambiguous we just return an error.
+ */
+ if (error == ERRNO_NO_LOCAL_MAPPING)
+ return (BSM_UNKNOWNERR);
+ bsme = au_bsm_error_lookup_errno(error);
+ if (bsme == NULL)
+ return (BSM_UNKNOWNERR);
+ return (bsme->be_bsm_error);
+}
+
+#if !defined(KERNEL) && !defined(_KERNEL)
+const char *
+au_strerror(u_char bsm_error)
+{
+ const struct bsm_errors *bsme;
+
+ bsme = au_bsm_error_lookup_bsm(bsm_error);
+ if (bsme == NULL)
+ return ("Unrecognized BSM error");
+ if (bsme->be_os_error != ERRNO_NO_LOCAL_MAPPING)
+ return (strerror(bsme->be_os_error));
+ return (bsme->be_strerror);
+}
+#endif
diff --git a/sys/security/audit/audit_bsm_klib.c b/sys/security/audit/audit_bsm_klib.c
new file mode 100644
index 0000000..a75a68b
--- /dev/null
+++ b/sys/security/audit/audit_bsm_klib.c
@@ -0,0 +1,580 @@
+/*
+ * Copyright (c) 1999-2008 Apple Inc.
+ * Copyright (c) 2005 Robert N. M. Watson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/fcntl.h>
+#include <sys/filedesc.h>
+#include <sys/libkern.h>
+#include <sys/malloc.h>
+#include <sys/mount.h>
+#include <sys/proc.h>
+#include <sys/rwlock.h>
+#include <sys/sem.h>
+#include <sys/sbuf.h>
+#include <sys/syscall.h>
+#include <sys/sysctl.h>
+#include <sys/sysent.h>
+#include <sys/vnode.h>
+
+#include <bsm/audit.h>
+#include <bsm/audit_kevents.h>
+#include <security/audit/audit.h>
+#include <security/audit/audit_private.h>
+
+/*
+ * Hash table functions for the audit event number to event class mask
+ * mapping.
+ */
+#define EVCLASSMAP_HASH_TABLE_SIZE 251
+struct evclass_elem {
+ au_event_t event;
+ au_class_t class;
+ LIST_ENTRY(evclass_elem) entry;
+};
+struct evclass_list {
+ LIST_HEAD(, evclass_elem) head;
+};
+
+static MALLOC_DEFINE(M_AUDITEVCLASS, "audit_evclass", "Audit event class");
+static struct rwlock evclass_lock;
+static struct evclass_list evclass_hash[EVCLASSMAP_HASH_TABLE_SIZE];
+
+#define EVCLASS_LOCK_INIT() rw_init(&evclass_lock, "evclass_lock")
+#define EVCLASS_RLOCK() rw_rlock(&evclass_lock)
+#define EVCLASS_RUNLOCK() rw_runlock(&evclass_lock)
+#define EVCLASS_WLOCK() rw_wlock(&evclass_lock)
+#define EVCLASS_WUNLOCK() rw_wunlock(&evclass_lock)
+
+/*
+ * Look up the class for an audit event in the class mapping table.
+ */
+au_class_t
+au_event_class(au_event_t event)
+{
+ struct evclass_list *evcl;
+ struct evclass_elem *evc;
+ au_class_t class;
+
+ EVCLASS_RLOCK();
+ evcl = &evclass_hash[event % EVCLASSMAP_HASH_TABLE_SIZE];
+ class = 0;
+ LIST_FOREACH(evc, &evcl->head, entry) {
+ if (evc->event == event) {
+ class = evc->class;
+ goto out;
+ }
+ }
+out:
+ EVCLASS_RUNLOCK();
+ return (class);
+}
+
+/*
+ * Insert a event to class mapping. If the event already exists in the
+ * mapping, then replace the mapping with the new one.
+ *
+ * XXX There is currently no constraints placed on the number of mappings.
+ * May want to either limit to a number, or in terms of memory usage.
+ */
+void
+au_evclassmap_insert(au_event_t event, au_class_t class)
+{
+ struct evclass_list *evcl;
+ struct evclass_elem *evc, *evc_new;
+
+ /*
+ * Pessimistically, always allocate storage before acquiring mutex.
+ * Free if there is already a mapping for this event.
+ */
+ evc_new = malloc(sizeof(*evc), M_AUDITEVCLASS, M_WAITOK);
+
+ EVCLASS_WLOCK();
+ evcl = &evclass_hash[event % EVCLASSMAP_HASH_TABLE_SIZE];
+ LIST_FOREACH(evc, &evcl->head, entry) {
+ if (evc->event == event) {
+ evc->class = class;
+ EVCLASS_WUNLOCK();
+ free(evc_new, M_AUDITEVCLASS);
+ return;
+ }
+ }
+ evc = evc_new;
+ evc->event = event;
+ evc->class = class;
+ LIST_INSERT_HEAD(&evcl->head, evc, entry);
+ EVCLASS_WUNLOCK();
+}
+
+void
+au_evclassmap_init(void)
+{
+ int i;
+
+ EVCLASS_LOCK_INIT();
+ for (i = 0; i < EVCLASSMAP_HASH_TABLE_SIZE; i++)
+ LIST_INIT(&evclass_hash[i].head);
+
+ /*
+ * Set up the initial event to class mapping for system calls.
+ *
+ * XXXRW: Really, this should walk all possible audit events, not all
+ * native ABI system calls, as there may be audit events reachable
+ * only through non-native system calls. It also seems a shame to
+ * frob the mutex this early.
+ */
+ for (i = 0; i < SYS_MAXSYSCALL; i++) {
+ if (sysent[i].sy_auevent != AUE_NULL)
+ au_evclassmap_insert(sysent[i].sy_auevent, 0);
+ }
+}
+
+/*
+ * Check whether an event is aditable by comparing the mask of classes this
+ * event is part of against the given mask.
+ */
+int
+au_preselect(au_event_t event, au_class_t class, au_mask_t *mask_p, int sorf)
+{
+ au_class_t effmask = 0;
+
+ if (mask_p == NULL)
+ return (-1);
+
+ /*
+ * Perform the actual check of the masks against the event.
+ */
+ if (sorf & AU_PRS_SUCCESS)
+ effmask |= (mask_p->am_success & class);
+
+ if (sorf & AU_PRS_FAILURE)
+ effmask |= (mask_p->am_failure & class);
+
+ if (effmask)
+ return (1);
+ else
+ return (0);
+}
+
+/*
+ * Convert sysctl names and present arguments to events.
+ */
+au_event_t
+audit_ctlname_to_sysctlevent(int name[], uint64_t valid_arg)
+{
+
+ /* can't parse it - so return the worst case */
+ if ((valid_arg & (ARG_CTLNAME | ARG_LEN)) != (ARG_CTLNAME | ARG_LEN))
+ return (AUE_SYSCTL);
+
+ switch (name[0]) {
+ /* non-admin "lookups" treat them special */
+ case KERN_OSTYPE:
+ case KERN_OSRELEASE:
+ case KERN_OSREV:
+ case KERN_VERSION:
+ case KERN_ARGMAX:
+ case KERN_CLOCKRATE:
+ case KERN_BOOTTIME:
+ case KERN_POSIX1:
+ case KERN_NGROUPS:
+ case KERN_JOB_CONTROL:
+ case KERN_SAVED_IDS:
+ case KERN_OSRELDATE:
+ case KERN_DUMMY:
+ return (AUE_SYSCTL_NONADMIN);
+
+ /* only treat the changeable controls as admin */
+ case KERN_MAXVNODES:
+ case KERN_MAXPROC:
+ case KERN_MAXFILES:
+ case KERN_MAXPROCPERUID:
+ case KERN_MAXFILESPERPROC:
+ case KERN_HOSTID:
+ case KERN_SECURELVL:
+ case KERN_HOSTNAME:
+ case KERN_VNODE:
+ case KERN_PROC:
+ case KERN_FILE:
+ case KERN_PROF:
+ case KERN_NISDOMAINNAME:
+ case KERN_UPDATEINTERVAL:
+ case KERN_NTP_PLL:
+ case KERN_BOOTFILE:
+ case KERN_DUMPDEV:
+ case KERN_IPC:
+ case KERN_PS_STRINGS:
+ case KERN_USRSTACK:
+ case KERN_LOGSIGEXIT:
+ case KERN_IOV_MAX:
+ case KERN_MAXID:
+ return ((valid_arg & ARG_VALUE) ?
+ AUE_SYSCTL : AUE_SYSCTL_NONADMIN);
+
+ default:
+ return (AUE_SYSCTL);
+ }
+ /* NOTREACHED */
+}
+
+/*
+ * Convert an open flags specifier into a specific type of open event for
+ * auditing purposes.
+ */
+au_event_t
+audit_flags_and_error_to_openevent(int oflags, int error)
+{
+ au_event_t aevent;
+
+ /*
+ * Need to check only those flags we care about.
+ */
+ oflags = oflags & (O_RDONLY | O_CREAT | O_TRUNC | O_RDWR | O_WRONLY);
+
+ /*
+ * These checks determine what flags are on with the condition that
+ * ONLY that combination is on, and no other flags are on.
+ */
+ switch (oflags) {
+ case O_RDONLY:
+ aevent = AUE_OPEN_R;
+ break;
+
+ case (O_RDONLY | O_CREAT):
+ aevent = AUE_OPEN_RC;
+ break;
+
+ case (O_RDONLY | O_CREAT | O_TRUNC):
+ aevent = AUE_OPEN_RTC;
+ break;
+
+ case (O_RDONLY | O_TRUNC):
+ aevent = AUE_OPEN_RT;
+ break;
+
+ case O_RDWR:
+ aevent = AUE_OPEN_RW;
+ break;
+
+ case (O_RDWR | O_CREAT):
+ aevent = AUE_OPEN_RWC;
+ break;
+
+ case (O_RDWR | O_CREAT | O_TRUNC):
+ aevent = AUE_OPEN_RWTC;
+ break;
+
+ case (O_RDWR | O_TRUNC):
+ aevent = AUE_OPEN_RWT;
+ break;
+
+ case O_WRONLY:
+ aevent = AUE_OPEN_W;
+ break;
+
+ case (O_WRONLY | O_CREAT):
+ aevent = AUE_OPEN_WC;
+ break;
+
+ case (O_WRONLY | O_CREAT | O_TRUNC):
+ aevent = AUE_OPEN_WTC;
+ break;
+
+ case (O_WRONLY | O_TRUNC):
+ aevent = AUE_OPEN_WT;
+ break;
+
+ default:
+ aevent = AUE_OPEN;
+ break;
+ }
+
+#if 0
+ /*
+ * Convert chatty errors to better matching events. Failures to
+ * find a file are really just attribute events -- so recast them as
+ * such.
+ *
+ * XXXAUDIT: Solaris defines that AUE_OPEN will never be returned, it
+ * is just a placeholder. However, in Darwin we return that in
+ * preference to other events. For now, comment this out as we don't
+ * have a BSM conversion routine for AUE_OPEN.
+ */
+ switch (aevent) {
+ case AUE_OPEN_R:
+ case AUE_OPEN_RT:
+ case AUE_OPEN_RW:
+ case AUE_OPEN_RWT:
+ case AUE_OPEN_W:
+ case AUE_OPEN_WT:
+ if (error == ENOENT)
+ aevent = AUE_OPEN;
+ }
+#endif
+ return (aevent);
+}
+
+/*
+ * Convert a MSGCTL command to a specific event.
+ */
+int
+audit_msgctl_to_event(int cmd)
+{
+
+ switch (cmd) {
+ case IPC_RMID:
+ return (AUE_MSGCTL_RMID);
+
+ case IPC_SET:
+ return (AUE_MSGCTL_SET);
+
+ case IPC_STAT:
+ return (AUE_MSGCTL_STAT);
+
+ default:
+ /* We will audit a bad command. */
+ return (AUE_MSGCTL);
+ }
+}
+
+/*
+ * Convert a SEMCTL command to a specific event.
+ */
+int
+audit_semctl_to_event(int cmd)
+{
+
+ switch (cmd) {
+ case GETALL:
+ return (AUE_SEMCTL_GETALL);
+
+ case GETNCNT:
+ return (AUE_SEMCTL_GETNCNT);
+
+ case GETPID:
+ return (AUE_SEMCTL_GETPID);
+
+ case GETVAL:
+ return (AUE_SEMCTL_GETVAL);
+
+ case GETZCNT:
+ return (AUE_SEMCTL_GETZCNT);
+
+ case IPC_RMID:
+ return (AUE_SEMCTL_RMID);
+
+ case IPC_SET:
+ return (AUE_SEMCTL_SET);
+
+ case SETALL:
+ return (AUE_SEMCTL_SETALL);
+
+ case SETVAL:
+ return (AUE_SEMCTL_SETVAL);
+
+ case IPC_STAT:
+ return (AUE_SEMCTL_STAT);
+
+ default:
+ /* We will audit a bad command. */
+ return (AUE_SEMCTL);
+ }
+}
+
+/*
+ * Convert a command for the auditon() system call to a audit event.
+ */
+int
+auditon_command_event(int cmd)
+{
+
+ switch(cmd) {
+ case A_GETPOLICY:
+ return (AUE_AUDITON_GPOLICY);
+
+ case A_SETPOLICY:
+ return (AUE_AUDITON_SPOLICY);
+
+ case A_GETKMASK:
+ return (AUE_AUDITON_GETKMASK);
+
+ case A_SETKMASK:
+ return (AUE_AUDITON_SETKMASK);
+
+ case A_GETQCTRL:
+ return (AUE_AUDITON_GQCTRL);
+
+ case A_SETQCTRL:
+ return (AUE_AUDITON_SQCTRL);
+
+ case A_GETCWD:
+ return (AUE_AUDITON_GETCWD);
+
+ case A_GETCAR:
+ return (AUE_AUDITON_GETCAR);
+
+ case A_GETSTAT:
+ return (AUE_AUDITON_GETSTAT);
+
+ case A_SETSTAT:
+ return (AUE_AUDITON_SETSTAT);
+
+ case A_SETUMASK:
+ return (AUE_AUDITON_SETUMASK);
+
+ case A_SETSMASK:
+ return (AUE_AUDITON_SETSMASK);
+
+ case A_GETCOND:
+ return (AUE_AUDITON_GETCOND);
+
+ case A_SETCOND:
+ return (AUE_AUDITON_SETCOND);
+
+ case A_GETCLASS:
+ return (AUE_AUDITON_GETCLASS);
+
+ case A_SETCLASS:
+ return (AUE_AUDITON_SETCLASS);
+
+ case A_GETPINFO:
+ case A_SETPMASK:
+ case A_SETFSIZE:
+ case A_GETFSIZE:
+ case A_GETPINFO_ADDR:
+ case A_GETKAUDIT:
+ case A_SETKAUDIT:
+ default:
+ return (AUE_AUDITON); /* No special record */
+ }
+}
+
+/*
+ * Create a canonical path from given path by prefixing either the root
+ * directory, or the current working directory. If the process working
+ * directory is NULL, we could use 'rootvnode' to obtain the root directory,
+ * but this results in a volfs name written to the audit log. So we will
+ * leave the filename starting with '/' in the audit log in this case.
+ */
+void
+audit_canon_path(struct thread *td, char *path, char *cpath)
+{
+ struct vnode *cvnp, *rvnp;
+ char *rbuf, *fbuf, *copy;
+ struct filedesc *fdp;
+ struct sbuf sbf;
+ int error, cwir;
+
+ WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, "%s: at %s:%d",
+ __func__, __FILE__, __LINE__);
+
+ copy = path;
+ rvnp = cvnp = NULL;
+ fdp = td->td_proc->p_fd;
+ FILEDESC_SLOCK(fdp);
+ /*
+ * Make sure that we handle the chroot(2) case. If there is an
+ * alternate root directory, prepend it to the audited pathname.
+ */
+ if (fdp->fd_rdir != NULL && fdp->fd_rdir != rootvnode) {
+ rvnp = fdp->fd_rdir;
+ vhold(rvnp);
+ }
+ /*
+ * If the supplied path is relative, make sure we capture the current
+ * working directory so we can prepend it to the supplied relative
+ * path.
+ */
+ if (*path != '/') {
+ cvnp = fdp->fd_cdir;
+ vhold(cvnp);
+ }
+ cwir = (fdp->fd_rdir == fdp->fd_cdir);
+ FILEDESC_SUNLOCK(fdp);
+ /*
+ * NB: We require that the supplied array be at least MAXPATHLEN bytes
+ * long. If this is not the case, then we can run into serious trouble.
+ */
+ (void) sbuf_new(&sbf, cpath, MAXPATHLEN, SBUF_FIXEDLEN);
+ /*
+ * Strip leading forward slashes.
+ */
+ while (*copy == '/')
+ copy++;
+ /*
+ * Make sure we handle chroot(2) and prepend the global path to these
+ * environments.
+ *
+ * NB: vn_fullpath(9) on FreeBSD is less reliable than vn_getpath(9)
+ * on Darwin. As a result, this may need some additional attention
+ * in the future.
+ */
+ if (rvnp != NULL) {
+ error = vn_fullpath_global(td, rvnp, &rbuf, &fbuf);
+ vdrop(rvnp);
+ if (error) {
+ cpath[0] = '\0';
+ if (cvnp != NULL)
+ vdrop(cvnp);
+ return;
+ }
+ (void) sbuf_cat(&sbf, rbuf);
+ free(fbuf, M_TEMP);
+ }
+ if (cvnp != NULL) {
+ error = vn_fullpath(td, cvnp, &rbuf, &fbuf);
+ vdrop(cvnp);
+ if (error) {
+ cpath[0] = '\0';
+ return;
+ }
+ (void) sbuf_cat(&sbf, rbuf);
+ free(fbuf, M_TEMP);
+ }
+ if (cwir == 0 || (cwir != 0 && cvnp == NULL))
+ (void) sbuf_putc(&sbf, '/');
+ /*
+ * Now that we have processed any alternate root and relative path
+ * names, add the supplied pathname.
+ */
+ (void) sbuf_cat(&sbf, copy);
+ /*
+ * One or more of the previous sbuf operations could have resulted in
+ * the supplied buffer being overflowed. Check to see if this is the
+ * case.
+ */
+ if (sbuf_overflowed(&sbf) != 0) {
+ cpath[0] = '\0';
+ return;
+ }
+ sbuf_finish(&sbf);
+}
diff --git a/sys/security/audit/audit_bsm_token.c b/sys/security/audit/audit_bsm_token.c
new file mode 100644
index 0000000..6733030
--- /dev/null
+++ b/sys/security/audit/audit_bsm_token.c
@@ -0,0 +1,1526 @@
+/*-
+ * Copyright (c) 2004-2008 Apple Inc.
+ * Copyright (c) 2005 SPARTA, Inc.
+ * All rights reserved.
+ *
+ * This code was developed in part by Robert N. M. Watson, Senior Principal
+ * Scientist, SPARTA, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * P4: //depot/projects/trustedbsd/openbsm/libbsm/bsm_token.c#72
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/endian.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+
+#include <sys/ipc.h>
+#include <sys/libkern.h>
+#include <sys/malloc.h>
+#include <sys/un.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+
+
+#include <bsm/audit.h>
+#include <bsm/audit_internal.h>
+#include <bsm/audit_record.h>
+#include <security/audit/audit.h>
+#include <security/audit/audit_private.h>
+
+#define GET_TOKEN_AREA(t, dptr, length) do { \
+ t = malloc(sizeof(token_t), M_AUDITBSM, M_WAITOK); \
+ t->t_data = malloc(length, M_AUDITBSM, M_WAITOK | M_ZERO); \
+ t->len = length; \
+ dptr = t->t_data; \
+} while (0)
+
+/*
+ * token ID 1 byte
+ * argument # 1 byte
+ * argument value 4 bytes/8 bytes (32-bit/64-bit value)
+ * text length 2 bytes
+ * text N bytes + 1 terminating NULL byte
+ */
+token_t *
+au_to_arg32(char n, const char *text, u_int32_t v)
+{
+ token_t *t;
+ u_char *dptr = NULL;
+ u_int16_t textlen;
+
+ textlen = strlen(text);
+ textlen += 1;
+
+ GET_TOKEN_AREA(t, dptr, 2 * sizeof(u_char) + sizeof(u_int32_t) +
+ sizeof(u_int16_t) + textlen);
+
+ ADD_U_CHAR(dptr, AUT_ARG32);
+ ADD_U_CHAR(dptr, n);
+ ADD_U_INT32(dptr, v);
+ ADD_U_INT16(dptr, textlen);
+ ADD_STRING(dptr, text, textlen);
+
+ return (t);
+}
+
+token_t *
+au_to_arg64(char n, const char *text, u_int64_t v)
+{
+ token_t *t;
+ u_char *dptr = NULL;
+ u_int16_t textlen;
+
+ textlen = strlen(text);
+ textlen += 1;
+
+ GET_TOKEN_AREA(t, dptr, 2 * sizeof(u_char) + sizeof(u_int64_t) +
+ sizeof(u_int16_t) + textlen);
+
+ ADD_U_CHAR(dptr, AUT_ARG64);
+ ADD_U_CHAR(dptr, n);
+ ADD_U_INT64(dptr, v);
+ ADD_U_INT16(dptr, textlen);
+ ADD_STRING(dptr, text, textlen);
+
+ return (t);
+}
+
+token_t *
+au_to_arg(char n, const char *text, u_int32_t v)
+{
+
+ return (au_to_arg32(n, text, v));
+}
+
+#if defined(_KERNEL) || defined(KERNEL)
+/*
+ * token ID 1 byte
+ * file access mode 4 bytes
+ * owner user ID 4 bytes
+ * owner group ID 4 bytes
+ * file system ID 4 bytes
+ * node ID 8 bytes
+ * device 4 bytes/8 bytes (32-bit/64-bit)
+ */
+token_t *
+au_to_attr32(struct vnode_au_info *vni)
+{
+ token_t *t;
+ u_char *dptr = NULL;
+ u_int16_t pad0_16 = 0;
+ u_int16_t pad0_32 = 0;
+
+ GET_TOKEN_AREA(t, dptr, sizeof(u_char) + 2 * sizeof(u_int16_t) +
+ 3 * sizeof(u_int32_t) + sizeof(u_int64_t) + sizeof(u_int32_t));
+
+ ADD_U_CHAR(dptr, AUT_ATTR32);
+
+ /*
+ * BSD defines the size for the file mode as 2 bytes; BSM defines 4
+ * so pad with 0.
+ *
+ * XXXRW: Possibly should be conditionally compiled.
+ *
+ * XXXRW: Should any conversions take place on the mode?
+ */
+ ADD_U_INT16(dptr, pad0_16);
+ ADD_U_INT16(dptr, vni->vn_mode);
+
+ ADD_U_INT32(dptr, vni->vn_uid);
+ ADD_U_INT32(dptr, vni->vn_gid);
+ ADD_U_INT32(dptr, vni->vn_fsid);
+
+ /*
+ * Some systems use 32-bit file ID's, others use 64-bit file IDs.
+ * Attempt to handle both, and let the compiler sort it out. If we
+ * could pick this out at compile-time, it would be better, so as to
+ * avoid the else case below.
+ */
+ if (sizeof(vni->vn_fileid) == sizeof(uint32_t)) {
+ ADD_U_INT32(dptr, pad0_32);
+ ADD_U_INT32(dptr, vni->vn_fileid);
+ } else if (sizeof(vni->vn_fileid) == sizeof(uint64_t))
+ ADD_U_INT64(dptr, vni->vn_fileid);
+ else
+ ADD_U_INT64(dptr, 0LL);
+
+ ADD_U_INT32(dptr, vni->vn_dev);
+
+ return (t);
+}
+
+token_t *
+au_to_attr64(struct vnode_au_info *vni)
+{
+ token_t *t;
+ u_char *dptr = NULL;
+ u_int16_t pad0_16 = 0;
+ u_int16_t pad0_32 = 0;
+
+ GET_TOKEN_AREA(t, dptr, sizeof(u_char) + 2 * sizeof(u_int16_t) +
+ 3 * sizeof(u_int32_t) + sizeof(u_int64_t) * 2);
+
+ ADD_U_CHAR(dptr, AUT_ATTR64);
+
+ /*
+ * BSD defines the size for the file mode as 2 bytes; BSM defines 4
+ * so pad with 0.
+ *
+ * XXXRW: Possibly should be conditionally compiled.
+ *
+ * XXXRW: Should any conversions take place on the mode?
+ */
+ ADD_U_INT16(dptr, pad0_16);
+ ADD_U_INT16(dptr, vni->vn_mode);
+
+ ADD_U_INT32(dptr, vni->vn_uid);
+ ADD_U_INT32(dptr, vni->vn_gid);
+ ADD_U_INT32(dptr, vni->vn_fsid);
+
+ /*
+ * Some systems use 32-bit file ID's, other's use 64-bit file IDs.
+ * Attempt to handle both, and let the compiler sort it out. If we
+ * could pick this out at compile-time, it would be better, so as to
+ * avoid the else case below.
+ */
+ if (sizeof(vni->vn_fileid) == sizeof(uint32_t)) {
+ ADD_U_INT32(dptr, pad0_32);
+ ADD_U_INT32(dptr, vni->vn_fileid);
+ } else if (sizeof(vni->vn_fileid) == sizeof(uint64_t))
+ ADD_U_INT64(dptr, vni->vn_fileid);
+ else
+ ADD_U_INT64(dptr, 0LL);
+
+ ADD_U_INT64(dptr, vni->vn_dev);
+
+ return (t);
+}
+
+token_t *
+au_to_attr(struct vnode_au_info *vni)
+{
+
+ return (au_to_attr32(vni));
+}
+#endif /* !(defined(_KERNEL) || defined(KERNEL) */
+
+/*
+ * token ID 1 byte
+ * how to print 1 byte
+ * basic unit 1 byte
+ * unit count 1 byte
+ * data items (depends on basic unit)
+ */
+token_t *
+au_to_data(char unit_print, char unit_type, char unit_count, const char *p)
+{
+ token_t *t;
+ u_char *dptr = NULL;
+ size_t datasize, totdata;
+
+ /* Determine the size of the basic unit. */
+ switch (unit_type) {
+ case AUR_BYTE:
+ /* case AUR_CHAR: */
+ datasize = AUR_BYTE_SIZE;
+ break;
+
+ case AUR_SHORT:
+ datasize = AUR_SHORT_SIZE;
+ break;
+
+ case AUR_INT32:
+ /* case AUR_INT: */
+ datasize = AUR_INT32_SIZE;
+ break;
+
+ case AUR_INT64:
+ datasize = AUR_INT64_SIZE;
+ break;
+
+ default:
+ return (NULL);
+ }
+
+ totdata = datasize * unit_count;
+
+ GET_TOKEN_AREA(t, dptr, 4 * sizeof(u_char) + totdata);
+
+ /*
+ * XXXRW: We should be byte-swapping each data item for multi-byte
+ * types.
+ */
+ ADD_U_CHAR(dptr, AUT_DATA);
+ ADD_U_CHAR(dptr, unit_print);
+ ADD_U_CHAR(dptr, unit_type);
+ ADD_U_CHAR(dptr, unit_count);
+ ADD_MEM(dptr, p, totdata);
+
+ return (t);
+}
+
+
+/*
+ * token ID 1 byte
+ * status 4 bytes
+ * return value 4 bytes
+ */
+token_t *
+au_to_exit(int retval, int err)
+{
+ token_t *t;
+ u_char *dptr = NULL;
+
+ GET_TOKEN_AREA(t, dptr, sizeof(u_char) + 2 * sizeof(u_int32_t));
+
+ ADD_U_CHAR(dptr, AUT_EXIT);
+ ADD_U_INT32(dptr, err);
+ ADD_U_INT32(dptr, retval);
+
+ return (t);
+}
+
+/*
+ */
+token_t *
+au_to_groups(int *groups)
+{
+
+ return (au_to_newgroups(AUDIT_MAX_GROUPS, (gid_t *)groups));
+}
+
+/*
+ * token ID 1 byte
+ * number groups 2 bytes
+ * group list count * 4 bytes
+ */
+token_t *
+au_to_newgroups(u_int16_t n, gid_t *groups)
+{
+ token_t *t;
+ u_char *dptr = NULL;
+ int i;
+
+ GET_TOKEN_AREA(t, dptr, sizeof(u_char) + sizeof(u_int16_t) +
+ n * sizeof(u_int32_t));
+
+ ADD_U_CHAR(dptr, AUT_NEWGROUPS);
+ ADD_U_INT16(dptr, n);
+ for (i = 0; i < n; i++)
+ ADD_U_INT32(dptr, groups[i]);
+
+ return (t);
+}
+
+/*
+ * token ID 1 byte
+ * internet address 4 bytes
+ */
+token_t *
+au_to_in_addr(struct in_addr *internet_addr)
+{
+ token_t *t;
+ u_char *dptr = NULL;
+
+ GET_TOKEN_AREA(t, dptr, sizeof(u_char) + sizeof(uint32_t));
+
+ ADD_U_CHAR(dptr, AUT_IN_ADDR);
+ ADD_MEM(dptr, &internet_addr->s_addr, sizeof(uint32_t));
+
+ return (t);
+}
+
+/*
+ * token ID 1 byte
+ * address type/length 4 bytes
+ * address 16 bytes
+ */
+token_t *
+au_to_in_addr_ex(struct in6_addr *internet_addr)
+{
+ token_t *t;
+ u_char *dptr = NULL;
+ u_int32_t type = AU_IPv6;
+
+ GET_TOKEN_AREA(t, dptr, sizeof(u_char) + 5 * sizeof(uint32_t));
+
+ ADD_U_CHAR(dptr, AUT_IN_ADDR_EX);
+ ADD_U_INT32(dptr, type);
+ ADD_MEM(dptr, internet_addr, 4 * sizeof(uint32_t));
+
+ return (t);
+}
+
+/*
+ * token ID 1 byte
+ * ip header 20 bytes
+ *
+ * The IP header should be submitted in network byte order.
+ */
+token_t *
+au_to_ip(struct ip *ip)
+{
+ token_t *t;
+ u_char *dptr = NULL;
+
+ GET_TOKEN_AREA(t, dptr, sizeof(u_char) + sizeof(struct ip));
+
+ ADD_U_CHAR(dptr, AUT_IP);
+ ADD_MEM(dptr, ip, sizeof(struct ip));
+
+ return (t);
+}
+
+/*
+ * token ID 1 byte
+ * object ID type 1 byte
+ * object ID 4 bytes
+ */
+token_t *
+au_to_ipc(char type, int id)
+{
+ token_t *t;
+ u_char *dptr = NULL;
+
+ GET_TOKEN_AREA(t, dptr, 2 * sizeof(u_char) + sizeof(u_int32_t));
+
+ ADD_U_CHAR(dptr, AUT_IPC);
+ ADD_U_CHAR(dptr, type);
+ ADD_U_INT32(dptr, id);
+
+ return (t);
+}
+
+/*
+ * token ID 1 byte
+ * owner user ID 4 bytes
+ * owner group ID 4 bytes
+ * creator user ID 4 bytes
+ * creator group ID 4 bytes
+ * access mode 4 bytes
+ * slot sequence # 4 bytes
+ * key 4 bytes
+ */
+token_t *
+au_to_ipc_perm(struct ipc_perm *perm)
+{
+ token_t *t;
+ u_char *dptr = NULL;
+ u_int16_t pad0 = 0;
+
+ GET_TOKEN_AREA(t, dptr, 12 * sizeof(u_int16_t) + sizeof(u_int32_t));
+
+ ADD_U_CHAR(dptr, AUT_IPC_PERM);
+
+ /*
+ * Systems vary significantly in what types they use in struct
+ * ipc_perm; at least a few still use 16-bit uid's and gid's, so
+ * allow for that, as BSM define 32-bit values here.
+ * Some systems define the sizes for ipc_perm members as 2 bytes;
+ * BSM defines 4 so pad with 0.
+ *
+ * XXXRW: Possibly shoulid be conditionally compiled, and more cases
+ * need to be handled.
+ */
+ if (sizeof(perm->uid) != sizeof(u_int32_t)) {
+ ADD_U_INT16(dptr, pad0);
+ ADD_U_INT16(dptr, perm->uid);
+ ADD_U_INT16(dptr, pad0);
+ ADD_U_INT16(dptr, perm->gid);
+ ADD_U_INT16(dptr, pad0);
+ ADD_U_INT16(dptr, perm->cuid);
+ ADD_U_INT16(dptr, pad0);
+ ADD_U_INT16(dptr, perm->cgid);
+ } else {
+ ADD_U_INT32(dptr, perm->uid);
+ ADD_U_INT32(dptr, perm->gid);
+ ADD_U_INT32(dptr, perm->cuid);
+ ADD_U_INT32(dptr, perm->cgid);
+ }
+
+ ADD_U_INT16(dptr, pad0);
+ ADD_U_INT16(dptr, perm->mode);
+
+ ADD_U_INT16(dptr, pad0);
+
+ ADD_U_INT16(dptr, perm->seq);
+
+ ADD_U_INT32(dptr, perm->key);
+
+ return (t);
+}
+
+/*
+ * token ID 1 byte
+ * port IP address 2 bytes
+ */
+token_t *
+au_to_iport(u_int16_t iport)
+{
+ token_t *t;
+ u_char *dptr = NULL;
+
+ GET_TOKEN_AREA(t, dptr, sizeof(u_char) + sizeof(u_int16_t));
+
+ ADD_U_CHAR(dptr, AUT_IPORT);
+ ADD_U_INT16(dptr, iport);
+
+ return (t);
+}
+
+/*
+ * token ID 1 byte
+ * size 2 bytes
+ * data size bytes
+ */
+token_t *
+au_to_opaque(const char *data, u_int16_t bytes)
+{
+ token_t *t;
+ u_char *dptr = NULL;
+
+ GET_TOKEN_AREA(t, dptr, sizeof(u_char) + sizeof(u_int16_t) + bytes);
+
+ ADD_U_CHAR(dptr, AUT_OPAQUE);
+ ADD_U_INT16(dptr, bytes);
+ ADD_MEM(dptr, data, bytes);
+
+ return (t);
+}
+
+/*
+ * token ID 1 byte
+ * seconds of time 4 bytes
+ * milliseconds of time 4 bytes
+ * file name len 2 bytes
+ * file pathname N bytes + 1 terminating NULL byte
+ */
+token_t *
+au_to_file(const char *file, struct timeval tm)
+{
+ token_t *t;
+ u_char *dptr = NULL;
+ u_int16_t filelen;
+ u_int32_t timems;
+
+ filelen = strlen(file);
+ filelen += 1;
+
+ GET_TOKEN_AREA(t, dptr, sizeof(u_char) + 2 * sizeof(u_int32_t) +
+ sizeof(u_int16_t) + filelen);
+
+ timems = tm.tv_usec/1000;
+
+ ADD_U_CHAR(dptr, AUT_OTHER_FILE32);
+ ADD_U_INT32(dptr, tm.tv_sec);
+ ADD_U_INT32(dptr, timems); /* We need time in ms. */
+ ADD_U_INT16(dptr, filelen);
+ ADD_STRING(dptr, file, filelen);
+
+ return (t);
+}
+
+/*
+ * token ID 1 byte
+ * text length 2 bytes
+ * text N bytes + 1 terminating NULL byte
+ */
+token_t *
+au_to_text(const char *text)
+{
+ token_t *t;
+ u_char *dptr = NULL;
+ u_int16_t textlen;
+
+ textlen = strlen(text);
+ textlen += 1;
+
+ /* XXXRW: Should validate length against token size limit. */
+
+ GET_TOKEN_AREA(t, dptr, sizeof(u_char) + sizeof(u_int16_t) + textlen);
+
+ ADD_U_CHAR(dptr, AUT_TEXT);
+ ADD_U_INT16(dptr, textlen);
+ ADD_STRING(dptr, text, textlen);
+
+ return (t);
+}
+
+/*
+ * token ID 1 byte
+ * path length 2 bytes
+ * path N bytes + 1 terminating NULL byte
+ */
+token_t *
+au_to_path(const char *text)
+{
+ token_t *t;
+ u_char *dptr = NULL;
+ u_int16_t textlen;
+
+ textlen = strlen(text);
+ textlen += 1;
+
+ GET_TOKEN_AREA(t, dptr, sizeof(u_char) + sizeof(u_int16_t) + textlen);
+
+ ADD_U_CHAR(dptr, AUT_PATH);
+ ADD_U_INT16(dptr, textlen);
+ ADD_STRING(dptr, text, textlen);
+
+ return (t);
+}
+
+/*
+ * token ID 1 byte
+ * audit ID 4 bytes
+ * effective user ID 4 bytes
+ * effective group ID 4 bytes
+ * real user ID 4 bytes
+ * real group ID 4 bytes
+ * process ID 4 bytes
+ * session ID 4 bytes
+ * terminal ID
+ * port ID 4 bytes/8 bytes (32-bit/64-bit value)
+ * machine address 4 bytes
+ */
+token_t *
+au_to_process32(au_id_t auid, uid_t euid, gid_t egid, uid_t ruid, gid_t rgid,
+ pid_t pid, au_asid_t sid, au_tid_t *tid)
+{
+ token_t *t;
+ u_char *dptr = NULL;
+
+ GET_TOKEN_AREA(t, dptr, sizeof(u_char) + 9 * sizeof(u_int32_t));
+
+ ADD_U_CHAR(dptr, AUT_PROCESS32);
+ ADD_U_INT32(dptr, auid);
+ ADD_U_INT32(dptr, euid);
+ ADD_U_INT32(dptr, egid);
+ ADD_U_INT32(dptr, ruid);
+ ADD_U_INT32(dptr, rgid);
+ ADD_U_INT32(dptr, pid);
+ ADD_U_INT32(dptr, sid);
+ ADD_U_INT32(dptr, tid->port);
+
+ /*
+ * Note: Solaris will write out IPv6 addresses here as a 32-bit
+ * address type and 16 bytes of address, but for IPv4 addresses it
+ * simply writes the 4-byte address directly. We support only IPv4
+ * addresses for process32 tokens.
+ */
+ ADD_MEM(dptr, &tid->machine, sizeof(u_int32_t));
+
+ return (t);
+}
+
+token_t *
+au_to_process64(au_id_t auid, uid_t euid, gid_t egid, uid_t ruid, gid_t rgid,
+ pid_t pid, au_asid_t sid, au_tid_t *tid)
+{
+ token_t *t;
+ u_char *dptr = NULL;
+
+ GET_TOKEN_AREA(t, dptr, sizeof(u_char) + 8 * sizeof(u_int32_t) +
+ sizeof(u_int64_t));
+
+ ADD_U_CHAR(dptr, AUT_PROCESS64);
+ ADD_U_INT32(dptr, auid);
+ ADD_U_INT32(dptr, euid);
+ ADD_U_INT32(dptr, egid);
+ ADD_U_INT32(dptr, ruid);
+ ADD_U_INT32(dptr, rgid);
+ ADD_U_INT32(dptr, pid);
+ ADD_U_INT32(dptr, sid);
+ ADD_U_INT64(dptr, tid->port);
+
+ /*
+ * Note: Solaris will write out IPv6 addresses here as a 32-bit
+ * address type and 16 bytes of address, but for IPv4 addresses it
+ * simply writes the 4-byte address directly. We support only IPv4
+ * addresses for process64 tokens.
+ */
+ ADD_MEM(dptr, &tid->machine, sizeof(u_int32_t));
+
+ return (t);
+}
+
+token_t *
+au_to_process(au_id_t auid, uid_t euid, gid_t egid, uid_t ruid, gid_t rgid,
+ pid_t pid, au_asid_t sid, au_tid_t *tid)
+{
+
+ return (au_to_process32(auid, euid, egid, ruid, rgid, pid, sid,
+ tid));
+}
+
+/*
+ * token ID 1 byte
+ * audit ID 4 bytes
+ * effective user ID 4 bytes
+ * effective group ID 4 bytes
+ * real user ID 4 bytes
+ * real group ID 4 bytes
+ * process ID 4 bytes
+ * session ID 4 bytes
+ * terminal ID
+ * port ID 4 bytes/8 bytes (32-bit/64-bit value)
+ * address type-len 4 bytes
+ * machine address 16 bytes
+ */
+token_t *
+au_to_process32_ex(au_id_t auid, uid_t euid, gid_t egid, uid_t ruid,
+ gid_t rgid, pid_t pid, au_asid_t sid, au_tid_addr_t *tid)
+{
+ token_t *t;
+ u_char *dptr = NULL;
+
+ KASSERT((tid->at_type == AU_IPv4) || (tid->at_type == AU_IPv6),
+ ("au_to_process32_ex: type %u", (unsigned int)tid->at_type));
+ if (tid->at_type == AU_IPv4)
+ GET_TOKEN_AREA(t, dptr, sizeof(u_char) +
+ 10 * sizeof(u_int32_t));
+ else
+ GET_TOKEN_AREA(t, dptr, sizeof(u_char) +
+ 13 * sizeof(u_int32_t));
+
+ ADD_U_CHAR(dptr, AUT_PROCESS32_EX);
+ ADD_U_INT32(dptr, auid);
+ ADD_U_INT32(dptr, euid);
+ ADD_U_INT32(dptr, egid);
+ ADD_U_INT32(dptr, ruid);
+ ADD_U_INT32(dptr, rgid);
+ ADD_U_INT32(dptr, pid);
+ ADD_U_INT32(dptr, sid);
+ ADD_U_INT32(dptr, tid->at_port);
+ ADD_U_INT32(dptr, tid->at_type);
+ ADD_MEM(dptr, &tid->at_addr[0], sizeof(u_int32_t));
+ if (tid->at_type == AU_IPv6) {
+ ADD_MEM(dptr, &tid->at_addr[1], sizeof(u_int32_t));
+ ADD_MEM(dptr, &tid->at_addr[2], sizeof(u_int32_t));
+ ADD_MEM(dptr, &tid->at_addr[3], sizeof(u_int32_t));
+ }
+
+ return (t);
+}
+
+token_t *
+au_to_process64_ex(au_id_t auid, uid_t euid, gid_t egid, uid_t ruid,
+ gid_t rgid, pid_t pid, au_asid_t sid, au_tid_addr_t *tid)
+{
+ token_t *t;
+ u_char *dptr = NULL;
+
+ if (tid->at_type == AU_IPv4)
+ GET_TOKEN_AREA(t, dptr, sizeof(u_char) +
+ 7 * sizeof(u_int32_t) + sizeof(u_int64_t) +
+ 2 * sizeof(u_int32_t));
+ else if (tid->at_type == AU_IPv6)
+ GET_TOKEN_AREA(t, dptr, sizeof(u_char) +
+ 7 * sizeof(u_int32_t) + sizeof(u_int64_t) +
+ 5 * sizeof(u_int32_t));
+ else
+ panic("au_to_process64_ex: invalidate at_type (%d)",
+ tid->at_type);
+
+ ADD_U_CHAR(dptr, AUT_PROCESS64_EX);
+ ADD_U_INT32(dptr, auid);
+ ADD_U_INT32(dptr, euid);
+ ADD_U_INT32(dptr, egid);
+ ADD_U_INT32(dptr, ruid);
+ ADD_U_INT32(dptr, rgid);
+ ADD_U_INT32(dptr, pid);
+ ADD_U_INT32(dptr, sid);
+ ADD_U_INT64(dptr, tid->at_port);
+ ADD_U_INT32(dptr, tid->at_type);
+ ADD_MEM(dptr, &tid->at_addr[0], sizeof(u_int32_t));
+ if (tid->at_type == AU_IPv6) {
+ ADD_MEM(dptr, &tid->at_addr[1], sizeof(u_int32_t));
+ ADD_MEM(dptr, &tid->at_addr[2], sizeof(u_int32_t));
+ ADD_MEM(dptr, &tid->at_addr[3], sizeof(u_int32_t));
+ }
+
+ return (t);
+}
+
+token_t *
+au_to_process_ex(au_id_t auid, uid_t euid, gid_t egid, uid_t ruid,
+ gid_t rgid, pid_t pid, au_asid_t sid, au_tid_addr_t *tid)
+{
+
+ return (au_to_process32_ex(auid, euid, egid, ruid, rgid, pid, sid,
+ tid));
+}
+
+/*
+ * token ID 1 byte
+ * error status 1 byte
+ * return value 4 bytes/8 bytes (32-bit/64-bit value)
+ */
+token_t *
+au_to_return32(char status, u_int32_t ret)
+{
+ token_t *t;
+ u_char *dptr = NULL;
+
+ GET_TOKEN_AREA(t, dptr, 2 * sizeof(u_char) + sizeof(u_int32_t));
+
+ ADD_U_CHAR(dptr, AUT_RETURN32);
+ ADD_U_CHAR(dptr, status);
+ ADD_U_INT32(dptr, ret);
+
+ return (t);
+}
+
+token_t *
+au_to_return64(char status, u_int64_t ret)
+{
+ token_t *t;
+ u_char *dptr = NULL;
+
+ GET_TOKEN_AREA(t, dptr, 2 * sizeof(u_char) + sizeof(u_int64_t));
+
+ ADD_U_CHAR(dptr, AUT_RETURN64);
+ ADD_U_CHAR(dptr, status);
+ ADD_U_INT64(dptr, ret);
+
+ return (t);
+}
+
+token_t *
+au_to_return(char status, u_int32_t ret)
+{
+
+ return (au_to_return32(status, ret));
+}
+
+/*
+ * token ID 1 byte
+ * sequence number 4 bytes
+ */
+token_t *
+au_to_seq(long audit_count)
+{
+ token_t *t;
+ u_char *dptr = NULL;
+
+ GET_TOKEN_AREA(t, dptr, sizeof(u_char) + sizeof(u_int32_t));
+
+ ADD_U_CHAR(dptr, AUT_SEQ);
+ ADD_U_INT32(dptr, audit_count);
+
+ return (t);
+}
+
+/*
+ * token ID 1 byte
+ * socket domain 2 bytes
+ * socket type 2 bytes
+ * address type 2 byte
+ * local port 2 bytes
+ * local address 4 bytes/16 bytes (IPv4/IPv6 address)
+ * remote port 2 bytes
+ * remote address 4 bytes/16 bytes (IPv4/IPv6 address)
+ */
+token_t *
+au_to_socket_ex(u_short so_domain, u_short so_type,
+ struct sockaddr *sa_local, struct sockaddr *sa_remote)
+{
+ token_t *t;
+ u_char *dptr = NULL;
+ struct sockaddr_in *sin;
+ struct sockaddr_in6 *sin6;
+
+ if (so_domain == AF_INET)
+ GET_TOKEN_AREA(t, dptr, sizeof(u_char) +
+ 5 * sizeof(u_int16_t) + 2 * sizeof(u_int32_t));
+ else if (so_domain == AF_INET6)
+ GET_TOKEN_AREA(t, dptr, sizeof(u_char) +
+ 5 * sizeof(u_int16_t) + 16 * sizeof(u_int32_t));
+ else
+ return (NULL);
+
+ ADD_U_CHAR(dptr, AUT_SOCKET_EX);
+ ADD_U_INT16(dptr, so_domain); /* XXXRW: explicitly convert? */
+ ADD_U_INT16(dptr, so_type); /* XXXRW: explicitly convert? */
+ if (so_domain == AF_INET) {
+ ADD_U_INT16(dptr, AU_IPv4);
+ sin = (struct sockaddr_in *)sa_local;
+ ADD_MEM(dptr, &sin->sin_port, sizeof(uint16_t));
+ ADD_MEM(dptr, &sin->sin_addr.s_addr, sizeof(uint32_t));
+ sin = (struct sockaddr_in *)sa_remote;
+ ADD_MEM(dptr, &sin->sin_port, sizeof(uint16_t));
+ ADD_MEM(dptr, &sin->sin_addr.s_addr, sizeof(uint32_t));
+ } else {
+ ADD_U_INT16(dptr, AU_IPv6);
+ sin6 = (struct sockaddr_in6 *)sa_local;
+ ADD_MEM(dptr, &sin6->sin6_port, sizeof(uint16_t));
+ ADD_MEM(dptr, &sin6->sin6_addr, 4 * sizeof(uint32_t));
+ sin6 = (struct sockaddr_in6 *)sa_remote;
+ ADD_MEM(dptr, &sin6->sin6_port, sizeof(uint16_t));
+ ADD_MEM(dptr, &sin6->sin6_addr, 4 * sizeof(uint32_t));
+ }
+
+ return (t);
+}
+
+/*
+ * Kernel-specific version of the above function.
+ *
+ * XXXRW: Should now use au_to_socket_ex() here.
+ */
+#ifdef _KERNEL
+token_t *
+kau_to_socket(struct socket_au_info *soi)
+{
+ token_t *t;
+ u_char *dptr;
+ u_int16_t so_type;
+
+ GET_TOKEN_AREA(t, dptr, sizeof(u_char) + 2 * sizeof(u_int16_t) +
+ sizeof(u_int32_t) + sizeof(u_int16_t) + sizeof(u_int32_t));
+
+ ADD_U_CHAR(dptr, AUT_SOCKET);
+ /* Coerce the socket type into a short value */
+ so_type = soi->so_type;
+ ADD_U_INT16(dptr, so_type);
+ ADD_U_INT16(dptr, soi->so_lport);
+ ADD_U_INT32(dptr, soi->so_laddr);
+ ADD_U_INT16(dptr, soi->so_rport);
+ ADD_U_INT32(dptr, soi->so_raddr);
+
+ return (t);
+}
+#endif
+
+/*
+ * token ID 1 byte
+ * socket family 2 bytes
+ * path 104 bytes
+ */
+token_t *
+au_to_sock_unix(struct sockaddr_un *so)
+{
+ token_t *t;
+ u_char *dptr;
+
+ GET_TOKEN_AREA(t, dptr, 3 * sizeof(u_char) + strlen(so->sun_path) + 1);
+
+ ADD_U_CHAR(dptr, AUT_SOCKUNIX);
+ /* BSM token has two bytes for family */
+ ADD_U_CHAR(dptr, 0);
+ ADD_U_CHAR(dptr, so->sun_family);
+ ADD_STRING(dptr, so->sun_path, strlen(so->sun_path) + 1);
+
+ return (t);
+}
+
+/*
+ * token ID 1 byte
+ * socket family 2 bytes
+ * local port 2 bytes
+ * socket address 4 bytes
+ */
+token_t *
+au_to_sock_inet32(struct sockaddr_in *so)
+{
+ token_t *t;
+ u_char *dptr = NULL;
+ uint16_t family;
+
+ GET_TOKEN_AREA(t, dptr, sizeof(u_char) + 2 * sizeof(uint16_t) +
+ sizeof(uint32_t));
+
+ ADD_U_CHAR(dptr, AUT_SOCKINET32);
+ /*
+ * BSM defines the family field as 16 bits, but many operating
+ * systems have an 8-bit sin_family field. Extend to 16 bits before
+ * writing into the token. Assume that both the port and the address
+ * in the sockaddr_in are already in network byte order, but family
+ * is in local byte order.
+ *
+ * XXXRW: Should a name space conversion be taking place on the value
+ * of sin_family?
+ */
+ family = so->sin_family;
+ ADD_U_INT16(dptr, family);
+ ADD_MEM(dptr, &so->sin_port, sizeof(uint16_t));
+ ADD_MEM(dptr, &so->sin_addr.s_addr, sizeof(uint32_t));
+
+ return (t);
+}
+
+token_t *
+au_to_sock_inet128(struct sockaddr_in6 *so)
+{
+ token_t *t;
+ u_char *dptr = NULL;
+
+ GET_TOKEN_AREA(t, dptr, 3 * sizeof(u_char) + sizeof(u_int16_t) +
+ 4 * sizeof(u_int32_t));
+
+ ADD_U_CHAR(dptr, AUT_SOCKINET128);
+ /*
+ * In BSD, sin6_family is one octet, but BSM defines the token to
+ * store two. So we copy in a 0 first. XXXRW: Possibly should be
+ * conditionally compiled.
+ */
+ ADD_U_CHAR(dptr, 0);
+ ADD_U_CHAR(dptr, so->sin6_family);
+
+ ADD_U_INT16(dptr, so->sin6_port);
+ ADD_MEM(dptr, &so->sin6_addr, 4 * sizeof(uint32_t));
+
+ return (t);
+}
+
+token_t *
+au_to_sock_inet(struct sockaddr_in *so)
+{
+
+ return (au_to_sock_inet32(so));
+}
+
+/*
+ * token ID 1 byte
+ * audit ID 4 bytes
+ * effective user ID 4 bytes
+ * effective group ID 4 bytes
+ * real user ID 4 bytes
+ * real group ID 4 bytes
+ * process ID 4 bytes
+ * session ID 4 bytes
+ * terminal ID
+ * port ID 4 bytes/8 bytes (32-bit/64-bit value)
+ * machine address 4 bytes
+ */
+token_t *
+au_to_subject32(au_id_t auid, uid_t euid, gid_t egid, uid_t ruid, gid_t rgid,
+ pid_t pid, au_asid_t sid, au_tid_t *tid)
+{
+ token_t *t;
+ u_char *dptr = NULL;
+
+ GET_TOKEN_AREA(t, dptr, sizeof(u_char) + 9 * sizeof(u_int32_t));
+
+ ADD_U_CHAR(dptr, AUT_SUBJECT32);
+ ADD_U_INT32(dptr, auid);
+ ADD_U_INT32(dptr, euid);
+ ADD_U_INT32(dptr, egid);
+ ADD_U_INT32(dptr, ruid);
+ ADD_U_INT32(dptr, rgid);
+ ADD_U_INT32(dptr, pid);
+ ADD_U_INT32(dptr, sid);
+ ADD_U_INT32(dptr, tid->port);
+ ADD_MEM(dptr, &tid->machine, sizeof(u_int32_t));
+
+ return (t);
+}
+
+token_t *
+au_to_subject64(au_id_t auid, uid_t euid, gid_t egid, uid_t ruid, gid_t rgid,
+ pid_t pid, au_asid_t sid, au_tid_t *tid)
+{
+ token_t *t;
+ u_char *dptr = NULL;
+
+ GET_TOKEN_AREA(t, dptr, sizeof(u_char) + 7 * sizeof(u_int32_t) +
+ sizeof(u_int64_t) + sizeof(u_int32_t));
+
+ ADD_U_CHAR(dptr, AUT_SUBJECT64);
+ ADD_U_INT32(dptr, auid);
+ ADD_U_INT32(dptr, euid);
+ ADD_U_INT32(dptr, egid);
+ ADD_U_INT32(dptr, ruid);
+ ADD_U_INT32(dptr, rgid);
+ ADD_U_INT32(dptr, pid);
+ ADD_U_INT32(dptr, sid);
+ ADD_U_INT64(dptr, tid->port);
+ ADD_MEM(dptr, &tid->machine, sizeof(u_int32_t));
+
+ return (t);
+}
+
+token_t *
+au_to_subject(au_id_t auid, uid_t euid, gid_t egid, uid_t ruid, gid_t rgid,
+ pid_t pid, au_asid_t sid, au_tid_t *tid)
+{
+
+ return (au_to_subject32(auid, euid, egid, ruid, rgid, pid, sid,
+ tid));
+}
+
+/*
+ * token ID 1 byte
+ * audit ID 4 bytes
+ * effective user ID 4 bytes
+ * effective group ID 4 bytes
+ * real user ID 4 bytes
+ * real group ID 4 bytes
+ * process ID 4 bytes
+ * session ID 4 bytes
+ * terminal ID
+ * port ID 4 bytes/8 bytes (32-bit/64-bit value)
+ * address type/length 4 bytes
+ * machine address 16 bytes
+ */
+token_t *
+au_to_subject32_ex(au_id_t auid, uid_t euid, gid_t egid, uid_t ruid,
+ gid_t rgid, pid_t pid, au_asid_t sid, au_tid_addr_t *tid)
+{
+ token_t *t;
+ u_char *dptr = NULL;
+
+ KASSERT((tid->at_type == AU_IPv4) || (tid->at_type == AU_IPv6),
+ ("au_to_subject32_ex: type %u", (unsigned int)tid->at_type));
+
+ if (tid->at_type == AU_IPv4)
+ GET_TOKEN_AREA(t, dptr, sizeof(u_char) + 10 *
+ sizeof(u_int32_t));
+ else
+ GET_TOKEN_AREA(t, dptr, sizeof(u_char) + 13 *
+ sizeof(u_int32_t));
+
+ ADD_U_CHAR(dptr, AUT_SUBJECT32_EX);
+ ADD_U_INT32(dptr, auid);
+ ADD_U_INT32(dptr, euid);
+ ADD_U_INT32(dptr, egid);
+ ADD_U_INT32(dptr, ruid);
+ ADD_U_INT32(dptr, rgid);
+ ADD_U_INT32(dptr, pid);
+ ADD_U_INT32(dptr, sid);
+ ADD_U_INT32(dptr, tid->at_port);
+ ADD_U_INT32(dptr, tid->at_type);
+ if (tid->at_type == AU_IPv6)
+ ADD_MEM(dptr, &tid->at_addr[0], 4 * sizeof(u_int32_t));
+ else
+ ADD_MEM(dptr, &tid->at_addr[0], sizeof(u_int32_t));
+
+ return (t);
+}
+
+token_t *
+au_to_subject64_ex(au_id_t auid, uid_t euid, gid_t egid, uid_t ruid,
+ gid_t rgid, pid_t pid, au_asid_t sid, au_tid_addr_t *tid)
+{
+ token_t *t;
+ u_char *dptr = NULL;
+
+ KASSERT((tid->at_type == AU_IPv4) || (tid->at_type == AU_IPv6),
+ ("au_to_subject64_ex: type %u", (unsigned int)tid->at_type));
+
+ if (tid->at_type == AU_IPv4)
+ GET_TOKEN_AREA(t, dptr, sizeof(u_char) +
+ 7 * sizeof(u_int32_t) + sizeof(u_int64_t) +
+ 2 * sizeof(u_int32_t));
+ else
+ GET_TOKEN_AREA(t, dptr, sizeof(u_char) +
+ 7 * sizeof(u_int32_t) + sizeof(u_int64_t) +
+ 5 * sizeof(u_int32_t));
+
+ ADD_U_CHAR(dptr, AUT_SUBJECT64_EX);
+ ADD_U_INT32(dptr, auid);
+ ADD_U_INT32(dptr, euid);
+ ADD_U_INT32(dptr, egid);
+ ADD_U_INT32(dptr, ruid);
+ ADD_U_INT32(dptr, rgid);
+ ADD_U_INT32(dptr, pid);
+ ADD_U_INT32(dptr, sid);
+ ADD_U_INT64(dptr, tid->at_port);
+ ADD_U_INT32(dptr, tid->at_type);
+ if (tid->at_type == AU_IPv6)
+ ADD_MEM(dptr, &tid->at_addr[0], 4 * sizeof(u_int32_t));
+ else
+ ADD_MEM(dptr, &tid->at_addr[0], sizeof(u_int32_t));
+
+ return (t);
+}
+
+token_t *
+au_to_subject_ex(au_id_t auid, uid_t euid, gid_t egid, uid_t ruid,
+ gid_t rgid, pid_t pid, au_asid_t sid, au_tid_addr_t *tid)
+{
+
+ return (au_to_subject32_ex(auid, euid, egid, ruid, rgid, pid, sid,
+ tid));
+}
+
+#if !defined(_KERNEL) && !defined(KERNEL) && defined(HAVE_AUDIT_SYSCALLS)
+/*
+ * Collects audit information for the current process and creates a subject
+ * token from it.
+ */
+token_t *
+au_to_me(void)
+{
+ auditinfo_t auinfo;
+
+ if (getaudit(&auinfo) != 0)
+ return (NULL);
+
+ return (au_to_subject32(auinfo.ai_auid, geteuid(), getegid(),
+ getuid(), getgid(), getpid(), auinfo.ai_asid, &auinfo.ai_termid));
+}
+#endif
+
+#if defined(_KERNEL) || defined(KERNEL)
+static token_t *
+au_to_exec_strings(char *strs, int count, u_char type)
+{
+ token_t *t;
+ u_char *dptr = NULL;
+ u_int32_t totlen;
+ int ctr;
+ char *p;
+
+ totlen = 0;
+ ctr = count;
+ p = strs;
+ while (ctr-- > 0) {
+ totlen += strlen(p) + 1;
+ p = strs + totlen;
+ }
+ GET_TOKEN_AREA(t, dptr, sizeof(u_char) + sizeof(u_int32_t) + totlen);
+ ADD_U_CHAR(dptr, type);
+ ADD_U_INT32(dptr, count);
+ ADD_STRING(dptr, strs, totlen);
+
+ return (t);
+}
+
+/*
+ * token ID 1 byte
+ * count 4 bytes
+ * text count null-terminated strings
+ */
+token_t *
+au_to_exec_args(char *args, int argc)
+{
+
+ return (au_to_exec_strings(args, argc, AUT_EXEC_ARGS));
+}
+
+/*
+ * token ID 1 byte
+ * count 4 bytes
+ * text count null-terminated strings
+ */
+token_t *
+au_to_exec_env(char *envs, int envc)
+{
+
+ return (au_to_exec_strings(envs, envc, AUT_EXEC_ENV));
+}
+#else
+/*
+ * token ID 1 byte
+ * count 4 bytes
+ * text count null-terminated strings
+ */
+token_t *
+au_to_exec_args(char **argv)
+{
+ token_t *t;
+ u_char *dptr = NULL;
+ const char *nextarg;
+ int i, count = 0;
+ size_t totlen = 0;
+
+ nextarg = *argv;
+
+ while (nextarg != NULL) {
+ int nextlen;
+
+ nextlen = strlen(nextarg);
+ totlen += nextlen + 1;
+ count++;
+ nextarg = *(argv + count);
+ }
+
+ GET_TOKEN_AREA(t, dptr, sizeof(u_char) + sizeof(u_int32_t) + totlen);
+
+ ADD_U_CHAR(dptr, AUT_EXEC_ARGS);
+ ADD_U_INT32(dptr, count);
+
+ for (i = 0; i < count; i++) {
+ nextarg = *(argv + i);
+ ADD_MEM(dptr, nextarg, strlen(nextarg) + 1);
+ }
+
+ return (t);
+}
+
+/*
+ * token ID 1 byte
+ * count 4 bytes
+ * text count null-terminated strings
+ */
+token_t *
+au_to_exec_env(char **envp)
+{
+ token_t *t;
+ u_char *dptr = NULL;
+ int i, count = 0;
+ size_t totlen = 0;
+ const char *nextenv;
+
+ nextenv = *envp;
+
+ while (nextenv != NULL) {
+ int nextlen;
+
+ nextlen = strlen(nextenv);
+ totlen += nextlen + 1;
+ count++;
+ nextenv = *(envp + count);
+ }
+
+ GET_TOKEN_AREA(t, dptr, sizeof(u_char) + sizeof(u_int32_t) + totlen);
+
+ ADD_U_CHAR(dptr, AUT_EXEC_ENV);
+ ADD_U_INT32(dptr, count);
+
+ for (i = 0; i < count; i++) {
+ nextenv = *(envp + i);
+ ADD_MEM(dptr, nextenv, strlen(nextenv) + 1);
+ }
+
+ return (t);
+}
+#endif
+
+/*
+ * token ID 1 byte
+ * zonename length 2 bytes
+ * zonename N bytes + 1 terminating NULL byte
+ */
+token_t *
+au_to_zonename(const char *zonename)
+{
+ u_char *dptr = NULL;
+ u_int16_t textlen;
+ token_t *t;
+
+ textlen = strlen(zonename) + 1;
+ GET_TOKEN_AREA(t, dptr, sizeof(u_char) + sizeof(u_int16_t) + textlen);
+
+ ADD_U_CHAR(dptr, AUT_ZONENAME);
+ ADD_U_INT16(dptr, textlen);
+ ADD_STRING(dptr, zonename, textlen);
+ return (t);
+}
+
+/*
+ * token ID 1 byte
+ * record byte count 4 bytes
+ * version # 1 byte [2]
+ * event type 2 bytes
+ * event modifier 2 bytes
+ * seconds of time 4 bytes/8 bytes (32-bit/64-bit value)
+ * milliseconds of time 4 bytes/8 bytes (32-bit/64-bit value)
+ */
+token_t *
+au_to_header32_tm(int rec_size, au_event_t e_type, au_emod_t e_mod,
+ struct timeval tm)
+{
+ token_t *t;
+ u_char *dptr = NULL;
+ u_int32_t timems;
+
+ GET_TOKEN_AREA(t, dptr, sizeof(u_char) + sizeof(u_int32_t) +
+ sizeof(u_char) + 2 * sizeof(u_int16_t) + 2 * sizeof(u_int32_t));
+
+ ADD_U_CHAR(dptr, AUT_HEADER32);
+ ADD_U_INT32(dptr, rec_size);
+ ADD_U_CHAR(dptr, AUDIT_HEADER_VERSION_OPENBSM);
+ ADD_U_INT16(dptr, e_type);
+ ADD_U_INT16(dptr, e_mod);
+
+ timems = tm.tv_usec/1000;
+ /* Add the timestamp */
+ ADD_U_INT32(dptr, tm.tv_sec);
+ ADD_U_INT32(dptr, timems); /* We need time in ms. */
+
+ return (t);
+}
+
+/*
+ * token ID 1 byte
+ * record byte count 4 bytes
+ * version # 1 byte [2]
+ * event type 2 bytes
+ * event modifier 2 bytes
+ * address type/length 4 bytes
+ * machine address 4 bytes/16 bytes (IPv4/IPv6 address)
+ * seconds of time 4 bytes/8 bytes (32-bit/64-bit value)
+ * milliseconds of time 4 bytes/8 bytes (32-bit/64-bit value)
+ */
+token_t *
+au_to_header32_ex_tm(int rec_size, au_event_t e_type, au_emod_t e_mod,
+ struct timeval tm, struct auditinfo_addr *aia)
+{
+ token_t *t;
+ u_char *dptr = NULL;
+ u_int32_t timems;
+ au_tid_addr_t *tid;
+
+ tid = &aia->ai_termid;
+ KASSERT(tid->at_type == AU_IPv4 || tid->at_type == AU_IPv6,
+ ("au_to_header32_ex_tm: invalid address family"));
+
+ GET_TOKEN_AREA(t, dptr, sizeof(u_char) + sizeof(u_int32_t) +
+ sizeof(u_char) + 2 * sizeof(u_int16_t) + 3 *
+ sizeof(u_int32_t) + tid->at_type);
+
+ ADD_U_CHAR(dptr, AUT_HEADER32_EX);
+ ADD_U_INT32(dptr, rec_size);
+ ADD_U_CHAR(dptr, AUDIT_HEADER_VERSION_OPENBSM);
+ ADD_U_INT16(dptr, e_type);
+ ADD_U_INT16(dptr, e_mod);
+
+ ADD_U_INT32(dptr, tid->at_type);
+ if (tid->at_type == AU_IPv6)
+ ADD_MEM(dptr, &tid->at_addr[0], 4 * sizeof(u_int32_t));
+ else
+ ADD_MEM(dptr, &tid->at_addr[0], sizeof(u_int32_t));
+ timems = tm.tv_usec/1000;
+ /* Add the timestamp */
+ ADD_U_INT32(dptr, tm.tv_sec);
+ ADD_U_INT32(dptr, timems); /* We need time in ms. */
+
+ return (t);
+}
+
+token_t *
+au_to_header64_tm(int rec_size, au_event_t e_type, au_emod_t e_mod,
+ struct timeval tm)
+{
+ token_t *t;
+ u_char *dptr = NULL;
+ u_int32_t timems;
+
+ GET_TOKEN_AREA(t, dptr, sizeof(u_char) + sizeof(u_int32_t) +
+ sizeof(u_char) + 2 * sizeof(u_int16_t) + 2 * sizeof(u_int64_t));
+
+ ADD_U_CHAR(dptr, AUT_HEADER64);
+ ADD_U_INT32(dptr, rec_size);
+ ADD_U_CHAR(dptr, AUDIT_HEADER_VERSION_OPENBSM);
+ ADD_U_INT16(dptr, e_type);
+ ADD_U_INT16(dptr, e_mod);
+
+ timems = tm.tv_usec/1000;
+ /* Add the timestamp */
+ ADD_U_INT64(dptr, tm.tv_sec);
+ ADD_U_INT64(dptr, timems); /* We need time in ms. */
+
+ return (t);
+}
+
+#if !defined(KERNEL) && !defined(_KERNEL)
+#ifdef HAVE_AUDIT_SYSCALLS
+token_t *
+au_to_header32_ex(int rec_size, au_event_t e_type, au_emod_t e_mod)
+{
+ struct timeval tm;
+ struct auditinfo_addr aia;
+
+ if (gettimeofday(&tm, NULL) == -1)
+ return (NULL);
+ if (auditon(A_GETKAUDIT, &aia, sizeof(aia)) < 0) {
+ if (errno != ENOSYS)
+ return (NULL);
+ return (au_to_header32_tm(rec_size, e_type, e_mod, tm));
+ }
+ return (au_to_header32_ex_tm(rec_size, e_type, e_mod, tm, &aia));
+}
+#endif /* HAVE_AUDIT_SYSCALLS */
+
+token_t *
+au_to_header32(int rec_size, au_event_t e_type, au_emod_t e_mod)
+{
+ struct timeval tm;
+
+ if (gettimeofday(&tm, NULL) == -1)
+ return (NULL);
+ return (au_to_header32_tm(rec_size, e_type, e_mod, tm));
+}
+
+token_t *
+au_to_header64(__unused int rec_size, __unused au_event_t e_type,
+ __unused au_emod_t e_mod)
+{
+ struct timeval tm;
+
+ if (gettimeofday(&tm, NULL) == -1)
+ return (NULL);
+ return (au_to_header64_tm(rec_size, e_type, e_mod, tm));
+}
+
+token_t *
+au_to_header(int rec_size, au_event_t e_type, au_emod_t e_mod)
+{
+
+ return (au_to_header32(rec_size, e_type, e_mod));
+}
+
+#ifdef HAVE_AUDIT_SYSCALLS
+token_t *
+au_to_header_ex(int rec_size, au_event_t e_type, au_emod_t e_mod)
+{
+
+ return (au_to_header32_ex(rec_size, e_type, e_mod));
+}
+#endif /* HAVE_AUDIT_SYSCALLS */
+#endif /* !defined(KERNEL) && !defined(_KERNEL) */
+
+/*
+ * token ID 1 byte
+ * trailer magic number 2 bytes
+ * record byte count 4 bytes
+ */
+token_t *
+au_to_trailer(int rec_size)
+{
+ token_t *t;
+ u_char *dptr = NULL;
+ u_int16_t magic = AUT_TRAILER_MAGIC;
+
+ GET_TOKEN_AREA(t, dptr, sizeof(u_char) + sizeof(u_int16_t) +
+ sizeof(u_int32_t));
+
+ ADD_U_CHAR(dptr, AUT_TRAILER);
+ ADD_U_INT16(dptr, magic);
+ ADD_U_INT32(dptr, rec_size);
+
+ return (t);
+}
diff --git a/sys/security/audit/audit_ioctl.h b/sys/security/audit/audit_ioctl.h
new file mode 100644
index 0000000..edf0339
--- /dev/null
+++ b/sys/security/audit/audit_ioctl.h
@@ -0,0 +1,83 @@
+/*-
+ * Copyright (c) 2006 Robert N. M. Watson
+ * All rights reserved.
+ *
+ * This software was developed by Robert Watson for the TrustedBSD Project.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _SECURITY_AUDIT_AUDIT_IOCTL_H_
+#define _SECURITY_AUDIT_AUDIT_IOCTL_H_
+
+#define AUDITPIPE_IOBASE 'A'
+
+/*
+ * Data structures used for complex ioctl arguments. Do not change existing
+ * structures, add new revised ones to be used by new ioctls, and keep the
+ * old structures and ioctls for backwards compatibility.
+ */
+struct auditpipe_ioctl_preselect {
+ au_id_t aip_auid;
+ au_mask_t aip_mask;
+};
+
+/*
+ * Possible modes of operation for audit pipe preselection.
+ */
+#define AUDITPIPE_PRESELECT_MODE_TRAIL 1 /* Global audit trail. */
+#define AUDITPIPE_PRESELECT_MODE_LOCAL 2 /* Local audit trail. */
+
+/*
+ * Ioctls to read and control the behavior of individual audit pipe devices.
+ */
+#define AUDITPIPE_GET_QLEN _IOR(AUDITPIPE_IOBASE, 1, u_int)
+#define AUDITPIPE_GET_QLIMIT _IOR(AUDITPIPE_IOBASE, 2, u_int)
+#define AUDITPIPE_SET_QLIMIT _IOW(AUDITPIPE_IOBASE, 3, u_int)
+#define AUDITPIPE_GET_QLIMIT_MIN _IOR(AUDITPIPE_IOBASE, 4, u_int)
+#define AUDITPIPE_GET_QLIMIT_MAX _IOR(AUDITPIPE_IOBASE, 5, u_int)
+#define AUDITPIPE_GET_PRESELECT_FLAGS _IOR(AUDITPIPE_IOBASE, 6, au_mask_t)
+#define AUDITPIPE_SET_PRESELECT_FLAGS _IOW(AUDITPIPE_IOBASE, 7, au_mask_t)
+#define AUDITPIPE_GET_PRESELECT_NAFLAGS _IOR(AUDITPIPE_IOBASE, 8, au_mask_t)
+#define AUDITPIPE_SET_PRESELECT_NAFLAGS _IOW(AUDITPIPE_IOBASE, 9, au_mask_t)
+#define AUDITPIPE_GET_PRESELECT_AUID _IOR(AUDITPIPE_IOBASE, 10, \
+ struct auditpipe_ioctl_preselect)
+#define AUDITPIPE_SET_PRESELECT_AUID _IOW(AUDITPIPE_IOBASE, 11, \
+ struct auditpipe_ioctl_preselect)
+#define AUDITPIPE_DELETE_PRESELECT_AUID _IOW(AUDITPIPE_IOBASE, 12, au_id_t)
+#define AUDITPIPE_FLUSH_PRESELECT_AUID _IO(AUDITPIPE_IOBASE, 13)
+#define AUDITPIPE_GET_PRESELECT_MODE _IOR(AUDITPIPE_IOBASE, 14, int)
+#define AUDITPIPE_SET_PRESELECT_MODE _IOW(AUDITPIPE_IOBASE, 15, int)
+#define AUDITPIPE_FLUSH _IO(AUDITPIPE_IOBASE, 16)
+#define AUDITPIPE_GET_MAXAUDITDATA _IOR(AUDITPIPE_IOBASE, 17, u_int)
+
+/*
+ * Ioctls to retrieve audit pipe statistics.
+ */
+#define AUDITPIPE_GET_INSERTS _IOR(AUDITPIPE_IOBASE, 100, u_int64_t)
+#define AUDITPIPE_GET_READS _IOR(AUDITPIPE_IOBASE, 101, u_int64_t)
+#define AUDITPIPE_GET_DROPS _IOR(AUDITPIPE_IOBASE, 102, u_int64_t)
+#define AUDITPIPE_GET_TRUNCATES _IOR(AUDITPIPE_IOBASE, 103, u_int64_t)
+
+#endif /* _SECURITY_AUDIT_AUDIT_IOCTL_H_ */
diff --git a/sys/security/audit/audit_pipe.c b/sys/security/audit/audit_pipe.c
new file mode 100644
index 0000000..f12a2b1
--- /dev/null
+++ b/sys/security/audit/audit_pipe.c
@@ -0,0 +1,1129 @@
+/*-
+ * Copyright (c) 2006 Robert N. M. Watson
+ * Copyright (c) 2008 Apple, Inc.
+ * All rights reserved.
+ *
+ * This software was developed by Robert Watson for the TrustedBSD Project.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/condvar.h>
+#include <sys/conf.h>
+#include <sys/eventhandler.h>
+#include <sys/filio.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/mutex.h>
+#include <sys/poll.h>
+#include <sys/proc.h>
+#include <sys/queue.h>
+#include <sys/rwlock.h>
+#include <sys/selinfo.h>
+#include <sys/sigio.h>
+#include <sys/signal.h>
+#include <sys/signalvar.h>
+#include <sys/sx.h>
+#include <sys/systm.h>
+#include <sys/uio.h>
+
+#include <security/audit/audit.h>
+#include <security/audit/audit_ioctl.h>
+#include <security/audit/audit_private.h>
+
+/*
+ * Implementation of a clonable special device providing a live stream of BSM
+ * audit data. Consumers receive a "tee" of the system audit trail by
+ * default, but may also define alternative event selections using ioctls.
+ * This interface provides unreliable but timely access to audit events.
+ * Consumers should be very careful to avoid introducing event cycles.
+ */
+
+/*
+ * Memory types.
+ */
+static MALLOC_DEFINE(M_AUDIT_PIPE, "audit_pipe", "Audit pipes");
+static MALLOC_DEFINE(M_AUDIT_PIPE_ENTRY, "audit_pipeent",
+ "Audit pipe entries and buffers");
+static MALLOC_DEFINE(M_AUDIT_PIPE_PRESELECT, "audit_pipe_presel",
+ "Audit pipe preselection structure");
+
+/*
+ * Audit pipe buffer parameters.
+ */
+#define AUDIT_PIPE_QLIMIT_DEFAULT (128)
+#define AUDIT_PIPE_QLIMIT_MIN (0)
+#define AUDIT_PIPE_QLIMIT_MAX (1024)
+
+/*
+ * Description of an entry in an audit_pipe.
+ */
+struct audit_pipe_entry {
+ void *ape_record;
+ u_int ape_record_len;
+ TAILQ_ENTRY(audit_pipe_entry) ape_queue;
+};
+
+/*
+ * Audit pipes allow processes to express "interest" in the set of records
+ * that are delivered via the pipe. They do this in a similar manner to the
+ * mechanism for audit trail configuration, by expressing two global masks,
+ * and optionally expressing per-auid masks. The following data structure is
+ * the per-auid mask description. The global state is stored in the audit
+ * pipe data structure.
+ *
+ * We may want to consider a more space/time-efficient data structure once
+ * usage patterns for per-auid specifications are clear.
+ */
+struct audit_pipe_preselect {
+ au_id_t app_auid;
+ au_mask_t app_mask;
+ TAILQ_ENTRY(audit_pipe_preselect) app_list;
+};
+
+/*
+ * Description of an individual audit_pipe. Consists largely of a bounded
+ * length queue.
+ */
+#define AUDIT_PIPE_ASYNC 0x00000001
+#define AUDIT_PIPE_NBIO 0x00000002
+struct audit_pipe {
+ int ap_open; /* Device open? */
+ u_int ap_flags;
+
+ struct selinfo ap_selinfo;
+ struct sigio *ap_sigio;
+
+ /*
+ * Per-pipe mutex protecting most fields in this data structure.
+ */
+ struct mtx ap_mtx;
+
+ /*
+ * Per-pipe sleep lock serializing user-generated reads and flushes.
+ * uiomove() is called to copy out the current head record's data
+ * while the record remains in the queue, so we prevent other threads
+ * from removing it using this lock.
+ */
+ struct sx ap_sx;
+
+ /*
+ * Condition variable to signal when data has been delivered to a
+ * pipe.
+ */
+ struct cv ap_cv;
+
+ /*
+ * Various queue-reated variables: qlen and qlimit are a count of
+ * records in the queue; qbyteslen is the number of bytes of data
+ * across all records, and qoffset is the amount read so far of the
+ * first record in the queue. The number of bytes available for
+ * reading in the queue is qbyteslen - qoffset.
+ */
+ u_int ap_qlen;
+ u_int ap_qlimit;
+ u_int ap_qbyteslen;
+ u_int ap_qoffset;
+
+ /*
+ * Per-pipe operation statistics.
+ */
+ u_int64_t ap_inserts; /* Records added. */
+ u_int64_t ap_reads; /* Records read. */
+ u_int64_t ap_drops; /* Records dropped. */
+
+ /*
+ * Fields relating to pipe interest: global masks for unmatched
+ * processes (attributable, non-attributable), and a list of specific
+ * interest specifications by auid.
+ */
+ int ap_preselect_mode;
+ au_mask_t ap_preselect_flags;
+ au_mask_t ap_preselect_naflags;
+ TAILQ_HEAD(, audit_pipe_preselect) ap_preselect_list;
+
+ /*
+ * Current pending record list. Protected by a combination of ap_mtx
+ * and ap_sx. Note particularly that *both* locks are required to
+ * remove a record from the head of the queue, as an in-progress read * may sleep while copying and therefore cannot hold ap_mtx.
+ */
+ TAILQ_HEAD(, audit_pipe_entry) ap_queue;
+
+ /*
+ * Global pipe list.
+ */
+ TAILQ_ENTRY(audit_pipe) ap_list;
+};
+
+#define AUDIT_PIPE_LOCK(ap) mtx_lock(&(ap)->ap_mtx)
+#define AUDIT_PIPE_LOCK_ASSERT(ap) mtx_assert(&(ap)->ap_mtx, MA_OWNED)
+#define AUDIT_PIPE_LOCK_DESTROY(ap) mtx_destroy(&(ap)->ap_mtx)
+#define AUDIT_PIPE_LOCK_INIT(ap) mtx_init(&(ap)->ap_mtx, \
+ "audit_pipe_mtx", NULL, MTX_DEF)
+#define AUDIT_PIPE_UNLOCK(ap) mtx_unlock(&(ap)->ap_mtx)
+#define AUDIT_PIPE_MTX(ap) (&(ap)->ap_mtx)
+
+#define AUDIT_PIPE_SX_LOCK_DESTROY(ap) sx_destroy(&(ap)->ap_sx)
+#define AUDIT_PIPE_SX_LOCK_INIT(ap) sx_init(&(ap)->ap_sx, "audit_pipe_sx")
+#define AUDIT_PIPE_SX_XLOCK_ASSERT(ap) sx_assert(&(ap)->ap_sx, SA_XLOCKED)
+#define AUDIT_PIPE_SX_XLOCK_SIG(ap) sx_xlock_sig(&(ap)->ap_sx)
+#define AUDIT_PIPE_SX_XUNLOCK(ap) sx_xunlock(&(ap)->ap_sx)
+
+/*
+ * Global list of audit pipes, rwlock to protect it. Individual record
+ * queues on pipes are protected by per-pipe locks; these locks synchronize
+ * between threads walking the list to deliver to individual pipes and add/
+ * remove of pipes, and are mostly acquired for read.
+ */
+static TAILQ_HEAD(, audit_pipe) audit_pipe_list;
+static struct rwlock audit_pipe_lock;
+
+#define AUDIT_PIPE_LIST_LOCK_INIT() rw_init(&audit_pipe_lock, \
+ "audit_pipe_list_lock")
+#define AUDIT_PIPE_LIST_RLOCK() rw_rlock(&audit_pipe_lock)
+#define AUDIT_PIPE_LIST_RUNLOCK() rw_runlock(&audit_pipe_lock)
+#define AUDIT_PIPE_LIST_WLOCK() rw_wlock(&audit_pipe_lock)
+#define AUDIT_PIPE_LIST_WLOCK_ASSERT() rw_assert(&audit_pipe_lock, \
+ RA_WLOCKED)
+#define AUDIT_PIPE_LIST_WUNLOCK() rw_wunlock(&audit_pipe_lock)
+
+/*
+ * Cloning related variables and constants.
+ */
+#define AUDIT_PIPE_NAME "auditpipe"
+static eventhandler_tag audit_pipe_eh_tag;
+static struct clonedevs *audit_pipe_clones;
+
+/*
+ * Special device methods and definition.
+ */
+static d_open_t audit_pipe_open;
+static d_close_t audit_pipe_close;
+static d_read_t audit_pipe_read;
+static d_ioctl_t audit_pipe_ioctl;
+static d_poll_t audit_pipe_poll;
+static d_kqfilter_t audit_pipe_kqfilter;
+
+static struct cdevsw audit_pipe_cdevsw = {
+ .d_version = D_VERSION,
+ .d_flags = D_PSEUDO | D_NEEDGIANT | D_NEEDMINOR,
+ .d_open = audit_pipe_open,
+ .d_close = audit_pipe_close,
+ .d_read = audit_pipe_read,
+ .d_ioctl = audit_pipe_ioctl,
+ .d_poll = audit_pipe_poll,
+ .d_kqfilter = audit_pipe_kqfilter,
+ .d_name = AUDIT_PIPE_NAME,
+};
+
+static int audit_pipe_kqread(struct knote *note, long hint);
+static void audit_pipe_kqdetach(struct knote *note);
+
+static struct filterops audit_pipe_read_filterops = {
+ .f_isfd = 1,
+ .f_attach = NULL,
+ .f_detach = audit_pipe_kqdetach,
+ .f_event = audit_pipe_kqread,
+};
+
+/*
+ * Some global statistics on audit pipes.
+ */
+static int audit_pipe_count; /* Current number of pipes. */
+static u_int64_t audit_pipe_ever; /* Pipes ever allocated. */
+static u_int64_t audit_pipe_records; /* Records seen. */
+static u_int64_t audit_pipe_drops; /* Global record drop count. */
+
+/*
+ * Free an audit pipe entry.
+ */
+static void
+audit_pipe_entry_free(struct audit_pipe_entry *ape)
+{
+
+ free(ape->ape_record, M_AUDIT_PIPE_ENTRY);
+ free(ape, M_AUDIT_PIPE_ENTRY);
+}
+
+/*
+ * Find an audit pipe preselection specification for an auid, if any.
+ */
+static struct audit_pipe_preselect *
+audit_pipe_preselect_find(struct audit_pipe *ap, au_id_t auid)
+{
+ struct audit_pipe_preselect *app;
+
+ AUDIT_PIPE_LOCK_ASSERT(ap);
+
+ TAILQ_FOREACH(app, &ap->ap_preselect_list, app_list) {
+ if (app->app_auid == auid)
+ return (app);
+ }
+ return (NULL);
+}
+
+/*
+ * Query the per-pipe mask for a specific auid.
+ */
+static int
+audit_pipe_preselect_get(struct audit_pipe *ap, au_id_t auid,
+ au_mask_t *maskp)
+{
+ struct audit_pipe_preselect *app;
+ int error;
+
+ AUDIT_PIPE_LOCK(ap);
+ app = audit_pipe_preselect_find(ap, auid);
+ if (app != NULL) {
+ *maskp = app->app_mask;
+ error = 0;
+ } else
+ error = ENOENT;
+ AUDIT_PIPE_UNLOCK(ap);
+ return (error);
+}
+
+/*
+ * Set the per-pipe mask for a specific auid. Add a new entry if needed;
+ * otherwise, update the current entry.
+ */
+static void
+audit_pipe_preselect_set(struct audit_pipe *ap, au_id_t auid, au_mask_t mask)
+{
+ struct audit_pipe_preselect *app, *app_new;
+
+ /*
+ * Pessimistically assume that the auid doesn't already have a mask
+ * set, and allocate. We will free it if it is unneeded.
+ */
+ app_new = malloc(sizeof(*app_new), M_AUDIT_PIPE_PRESELECT, M_WAITOK);
+ AUDIT_PIPE_LOCK(ap);
+ app = audit_pipe_preselect_find(ap, auid);
+ if (app == NULL) {
+ app = app_new;
+ app_new = NULL;
+ app->app_auid = auid;
+ TAILQ_INSERT_TAIL(&ap->ap_preselect_list, app, app_list);
+ }
+ app->app_mask = mask;
+ AUDIT_PIPE_UNLOCK(ap);
+ if (app_new != NULL)
+ free(app_new, M_AUDIT_PIPE_PRESELECT);
+}
+
+/*
+ * Delete a per-auid mask on an audit pipe.
+ */
+static int
+audit_pipe_preselect_delete(struct audit_pipe *ap, au_id_t auid)
+{
+ struct audit_pipe_preselect *app;
+ int error;
+
+ AUDIT_PIPE_LOCK(ap);
+ app = audit_pipe_preselect_find(ap, auid);
+ if (app != NULL) {
+ TAILQ_REMOVE(&ap->ap_preselect_list, app, app_list);
+ error = 0;
+ } else
+ error = ENOENT;
+ AUDIT_PIPE_UNLOCK(ap);
+ if (app != NULL)
+ free(app, M_AUDIT_PIPE_PRESELECT);
+ return (error);
+}
+
+/*
+ * Delete all per-auid masks on an audit pipe.
+ */
+static void
+audit_pipe_preselect_flush_locked(struct audit_pipe *ap)
+{
+ struct audit_pipe_preselect *app;
+
+ AUDIT_PIPE_LOCK_ASSERT(ap);
+
+ while ((app = TAILQ_FIRST(&ap->ap_preselect_list)) != NULL) {
+ TAILQ_REMOVE(&ap->ap_preselect_list, app, app_list);
+ free(app, M_AUDIT_PIPE_PRESELECT);
+ }
+}
+
+static void
+audit_pipe_preselect_flush(struct audit_pipe *ap)
+{
+
+ AUDIT_PIPE_LOCK(ap);
+ audit_pipe_preselect_flush_locked(ap);
+ AUDIT_PIPE_UNLOCK(ap);
+}
+
+/*-
+ * Determine whether a specific audit pipe matches a record with these
+ * properties. Algorithm is as follows:
+ *
+ * - If the pipe is configured to track the default trail configuration, then
+ * use the results of global preselection matching.
+ * - If not, search for a specifically configured auid entry matching the
+ * event. If an entry is found, use that.
+ * - Otherwise, use the default flags or naflags configured for the pipe.
+ */
+static int
+audit_pipe_preselect_check(struct audit_pipe *ap, au_id_t auid,
+ au_event_t event, au_class_t class, int sorf, int trail_preselect)
+{
+ struct audit_pipe_preselect *app;
+
+ AUDIT_PIPE_LOCK_ASSERT(ap);
+
+ switch (ap->ap_preselect_mode) {
+ case AUDITPIPE_PRESELECT_MODE_TRAIL:
+ return (trail_preselect);
+
+ case AUDITPIPE_PRESELECT_MODE_LOCAL:
+ app = audit_pipe_preselect_find(ap, auid);
+ if (app == NULL) {
+ if (auid == AU_DEFAUDITID)
+ return (au_preselect(event, class,
+ &ap->ap_preselect_naflags, sorf));
+ else
+ return (au_preselect(event, class,
+ &ap->ap_preselect_flags, sorf));
+ } else
+ return (au_preselect(event, class, &app->app_mask,
+ sorf));
+
+ default:
+ panic("audit_pipe_preselect_check: mode %d",
+ ap->ap_preselect_mode);
+ }
+
+ return (0);
+}
+
+/*
+ * Determine whether there exists a pipe interested in a record with specific
+ * properties.
+ */
+int
+audit_pipe_preselect(au_id_t auid, au_event_t event, au_class_t class,
+ int sorf, int trail_preselect)
+{
+ struct audit_pipe *ap;
+
+ AUDIT_PIPE_LIST_RLOCK();
+ TAILQ_FOREACH(ap, &audit_pipe_list, ap_list) {
+ AUDIT_PIPE_LOCK(ap);
+ if (audit_pipe_preselect_check(ap, auid, event, class, sorf,
+ trail_preselect)) {
+ AUDIT_PIPE_UNLOCK(ap);
+ AUDIT_PIPE_LIST_RUNLOCK();
+ return (1);
+ }
+ AUDIT_PIPE_UNLOCK(ap);
+ }
+ AUDIT_PIPE_LIST_RUNLOCK();
+ return (0);
+}
+
+/*
+ * Append individual record to a queue -- allocate queue-local buffer, and
+ * add to the queue. If the queue is full or we can't allocate memory, drop
+ * the newest record.
+ */
+static void
+audit_pipe_append(struct audit_pipe *ap, void *record, u_int record_len)
+{
+ struct audit_pipe_entry *ape;
+
+ AUDIT_PIPE_LOCK_ASSERT(ap);
+
+ if (ap->ap_qlen >= ap->ap_qlimit) {
+ ap->ap_drops++;
+ audit_pipe_drops++;
+ return;
+ }
+
+ ape = malloc(sizeof(*ape), M_AUDIT_PIPE_ENTRY, M_NOWAIT | M_ZERO);
+ if (ape == NULL) {
+ ap->ap_drops++;
+ audit_pipe_drops++;
+ return;
+ }
+
+ ape->ape_record = malloc(record_len, M_AUDIT_PIPE_ENTRY, M_NOWAIT);
+ if (ape->ape_record == NULL) {
+ free(ape, M_AUDIT_PIPE_ENTRY);
+ ap->ap_drops++;
+ audit_pipe_drops++;
+ return;
+ }
+
+ bcopy(record, ape->ape_record, record_len);
+ ape->ape_record_len = record_len;
+
+ TAILQ_INSERT_TAIL(&ap->ap_queue, ape, ape_queue);
+ ap->ap_inserts++;
+ ap->ap_qlen++;
+ ap->ap_qbyteslen += ape->ape_record_len;
+ selwakeuppri(&ap->ap_selinfo, PSOCK);
+ KNOTE_LOCKED(&ap->ap_selinfo.si_note, 0);
+ if (ap->ap_flags & AUDIT_PIPE_ASYNC)
+ pgsigio(&ap->ap_sigio, SIGIO, 0);
+ cv_broadcast(&ap->ap_cv);
+}
+
+/*
+ * audit_pipe_submit(): audit_worker submits audit records via this
+ * interface, which arranges for them to be delivered to pipe queues.
+ */
+void
+audit_pipe_submit(au_id_t auid, au_event_t event, au_class_t class, int sorf,
+ int trail_select, void *record, u_int record_len)
+{
+ struct audit_pipe *ap;
+
+ /*
+ * Lockless read to avoid lock overhead if pipes are not in use.
+ */
+ if (TAILQ_FIRST(&audit_pipe_list) == NULL)
+ return;
+
+ AUDIT_PIPE_LIST_RLOCK();
+ TAILQ_FOREACH(ap, &audit_pipe_list, ap_list) {
+ AUDIT_PIPE_LOCK(ap);
+ if (audit_pipe_preselect_check(ap, auid, event, class, sorf,
+ trail_select))
+ audit_pipe_append(ap, record, record_len);
+ AUDIT_PIPE_UNLOCK(ap);
+ }
+ AUDIT_PIPE_LIST_RUNLOCK();
+
+ /* Unlocked increment. */
+ audit_pipe_records++;
+}
+
+/*
+ * audit_pipe_submit_user(): the same as audit_pipe_submit(), except that
+ * since we don't currently have selection information available, it is
+ * delivered to the pipe unconditionally.
+ *
+ * XXXRW: This is a bug. The BSM check routine for submitting a user record
+ * should parse that information and return it.
+ */
+void
+audit_pipe_submit_user(void *record, u_int record_len)
+{
+ struct audit_pipe *ap;
+
+ /*
+ * Lockless read to avoid lock overhead if pipes are not in use.
+ */
+ if (TAILQ_FIRST(&audit_pipe_list) == NULL)
+ return;
+
+ AUDIT_PIPE_LIST_RLOCK();
+ TAILQ_FOREACH(ap, &audit_pipe_list, ap_list) {
+ AUDIT_PIPE_LOCK(ap);
+ audit_pipe_append(ap, record, record_len);
+ AUDIT_PIPE_UNLOCK(ap);
+ }
+ AUDIT_PIPE_LIST_RUNLOCK();
+
+ /* Unlocked increment. */
+ audit_pipe_records++;
+}
+
+/*
+ * Allocate a new audit pipe. Connects the pipe, on success, to the global
+ * list and updates statistics.
+ */
+static struct audit_pipe *
+audit_pipe_alloc(void)
+{
+ struct audit_pipe *ap;
+
+ AUDIT_PIPE_LIST_WLOCK_ASSERT();
+
+ ap = malloc(sizeof(*ap), M_AUDIT_PIPE, M_NOWAIT | M_ZERO);
+ if (ap == NULL)
+ return (NULL);
+ ap->ap_qlimit = AUDIT_PIPE_QLIMIT_DEFAULT;
+ TAILQ_INIT(&ap->ap_queue);
+ knlist_init(&ap->ap_selinfo.si_note, AUDIT_PIPE_MTX(ap), NULL, NULL,
+ NULL);
+ AUDIT_PIPE_LOCK_INIT(ap);
+ AUDIT_PIPE_SX_LOCK_INIT(ap);
+ cv_init(&ap->ap_cv, "audit_pipe");
+
+ /*
+ * Default flags, naflags, and auid-specific preselection settings to
+ * 0. Initialize the mode to the global trail so that if praudit(1)
+ * is run on /dev/auditpipe, it sees events associated with the
+ * default trail. Pipe-aware application can clear the flag, set
+ * custom masks, and flush the pipe as needed.
+ */
+ bzero(&ap->ap_preselect_flags, sizeof(ap->ap_preselect_flags));
+ bzero(&ap->ap_preselect_naflags, sizeof(ap->ap_preselect_naflags));
+ TAILQ_INIT(&ap->ap_preselect_list);
+ ap->ap_preselect_mode = AUDITPIPE_PRESELECT_MODE_TRAIL;
+
+ /*
+ * Add to global list and update global statistics.
+ */
+ TAILQ_INSERT_HEAD(&audit_pipe_list, ap, ap_list);
+ audit_pipe_count++;
+ audit_pipe_ever++;
+
+ return (ap);
+}
+
+/*
+ * Flush all records currently present in an audit pipe; assume mutex is held.
+ */
+static void
+audit_pipe_flush(struct audit_pipe *ap)
+{
+ struct audit_pipe_entry *ape;
+
+ AUDIT_PIPE_LOCK_ASSERT(ap);
+
+ while ((ape = TAILQ_FIRST(&ap->ap_queue)) != NULL) {
+ TAILQ_REMOVE(&ap->ap_queue, ape, ape_queue);
+ ap->ap_qbyteslen -= ape->ape_record_len;
+ audit_pipe_entry_free(ape);
+ ap->ap_qlen--;
+ }
+ ap->ap_qoffset = 0;
+
+ KASSERT(ap->ap_qlen == 0, ("audit_pipe_free: ap_qbyteslen"));
+ KASSERT(ap->ap_qbyteslen == 0, ("audit_pipe_flush: ap_qbyteslen"));
+}
+
+/*
+ * Free an audit pipe; this means freeing all preselection state and all
+ * records in the pipe. Assumes global write lock and pipe mutex are held to
+ * prevent any new records from being inserted during the free, and that the
+ * audit pipe is still on the global list.
+ */
+static void
+audit_pipe_free(struct audit_pipe *ap)
+{
+
+ AUDIT_PIPE_LIST_WLOCK_ASSERT();
+ AUDIT_PIPE_LOCK_ASSERT(ap);
+
+ audit_pipe_preselect_flush_locked(ap);
+ audit_pipe_flush(ap);
+ cv_destroy(&ap->ap_cv);
+ AUDIT_PIPE_SX_LOCK_DESTROY(ap);
+ AUDIT_PIPE_LOCK_DESTROY(ap);
+ knlist_destroy(&ap->ap_selinfo.si_note);
+ TAILQ_REMOVE(&audit_pipe_list, ap, ap_list);
+ free(ap, M_AUDIT_PIPE);
+ audit_pipe_count--;
+}
+
+/*
+ * Audit pipe clone routine -- provide specific requested audit pipe, or a
+ * fresh one if a specific one is not requested.
+ */
+static void
+audit_pipe_clone(void *arg, struct ucred *cred, char *name, int namelen,
+ struct cdev **dev)
+{
+ int i, u;
+
+ if (*dev != NULL)
+ return;
+
+ if (strcmp(name, AUDIT_PIPE_NAME) == 0)
+ u = -1;
+ else if (dev_stdclone(name, NULL, AUDIT_PIPE_NAME, &u) != 1)
+ return;
+
+ i = clone_create(&audit_pipe_clones, &audit_pipe_cdevsw, &u, dev, 0);
+ if (i) {
+ *dev = make_dev(&audit_pipe_cdevsw, u, UID_ROOT,
+ GID_WHEEL, 0600, "%s%d", AUDIT_PIPE_NAME, u);
+ if (*dev != NULL) {
+ dev_ref(*dev);
+ (*dev)->si_flags |= SI_CHEAPCLONE;
+ }
+ }
+}
+
+/*
+ * Audit pipe open method. Explicit privilege check isn't used as this
+ * allows file permissions on the special device to be used to grant audit
+ * review access. Those file permissions should be managed carefully.
+ */
+static int
+audit_pipe_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
+{
+ struct audit_pipe *ap;
+
+ AUDIT_PIPE_LIST_WLOCK();
+ ap = dev->si_drv1;
+ if (ap == NULL) {
+ ap = audit_pipe_alloc();
+ if (ap == NULL) {
+ AUDIT_PIPE_LIST_WUNLOCK();
+ return (ENOMEM);
+ }
+ dev->si_drv1 = ap;
+ } else {
+ KASSERT(ap->ap_open, ("audit_pipe_open: ap && !ap_open"));
+ AUDIT_PIPE_LIST_WUNLOCK();
+ return (EBUSY);
+ }
+ ap->ap_open = 1; /* No lock required yet. */
+ AUDIT_PIPE_LIST_WUNLOCK();
+ fsetown(td->td_proc->p_pid, &ap->ap_sigio);
+ return (0);
+}
+
+/*
+ * Close audit pipe, tear down all records, etc.
+ */
+static int
+audit_pipe_close(struct cdev *dev, int fflag, int devtype, struct thread *td)
+{
+ struct audit_pipe *ap;
+
+ ap = dev->si_drv1;
+ KASSERT(ap != NULL, ("audit_pipe_close: ap == NULL"));
+ KASSERT(ap->ap_open, ("audit_pipe_close: !ap_open"));
+
+ funsetown(&ap->ap_sigio);
+ AUDIT_PIPE_LIST_WLOCK();
+ AUDIT_PIPE_LOCK(ap);
+ ap->ap_open = 0;
+ audit_pipe_free(ap);
+ dev->si_drv1 = NULL;
+ AUDIT_PIPE_LIST_WUNLOCK();
+ return (0);
+}
+
+/*
+ * Audit pipe ioctl() routine. Handle file descriptor and audit pipe layer
+ * commands.
+ */
+static int
+audit_pipe_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag,
+ struct thread *td)
+{
+ struct auditpipe_ioctl_preselect *aip;
+ struct audit_pipe *ap;
+ au_mask_t *maskp;
+ int error, mode;
+ au_id_t auid;
+
+ ap = dev->si_drv1;
+ KASSERT(ap != NULL, ("audit_pipe_ioctl: ap == NULL"));
+
+ /*
+ * Audit pipe ioctls: first come standard device node ioctls, then
+ * manipulation of pipe settings, and finally, statistics query
+ * ioctls.
+ */
+ switch (cmd) {
+ case FIONBIO:
+ AUDIT_PIPE_LOCK(ap);
+ if (*(int *)data)
+ ap->ap_flags |= AUDIT_PIPE_NBIO;
+ else
+ ap->ap_flags &= ~AUDIT_PIPE_NBIO;
+ AUDIT_PIPE_UNLOCK(ap);
+ error = 0;
+ break;
+
+ case FIONREAD:
+ AUDIT_PIPE_LOCK(ap);
+ *(int *)data = ap->ap_qbyteslen - ap->ap_qoffset;
+ AUDIT_PIPE_UNLOCK(ap);
+ error = 0;
+ break;
+
+ case FIOASYNC:
+ AUDIT_PIPE_LOCK(ap);
+ if (*(int *)data)
+ ap->ap_flags |= AUDIT_PIPE_ASYNC;
+ else
+ ap->ap_flags &= ~AUDIT_PIPE_ASYNC;
+ AUDIT_PIPE_UNLOCK(ap);
+ error = 0;
+ break;
+
+ case FIOSETOWN:
+ error = fsetown(*(int *)data, &ap->ap_sigio);
+ break;
+
+ case FIOGETOWN:
+ *(int *)data = fgetown(&ap->ap_sigio);
+ error = 0;
+ break;
+
+ case AUDITPIPE_GET_QLEN:
+ *(u_int *)data = ap->ap_qlen;
+ error = 0;
+ break;
+
+ case AUDITPIPE_GET_QLIMIT:
+ *(u_int *)data = ap->ap_qlimit;
+ error = 0;
+ break;
+
+ case AUDITPIPE_SET_QLIMIT:
+ /* Lockless integer write. */
+ if (*(u_int *)data >= AUDIT_PIPE_QLIMIT_MIN ||
+ *(u_int *)data <= AUDIT_PIPE_QLIMIT_MAX) {
+ ap->ap_qlimit = *(u_int *)data;
+ error = 0;
+ } else
+ error = EINVAL;
+ break;
+
+ case AUDITPIPE_GET_QLIMIT_MIN:
+ *(u_int *)data = AUDIT_PIPE_QLIMIT_MIN;
+ error = 0;
+ break;
+
+ case AUDITPIPE_GET_QLIMIT_MAX:
+ *(u_int *)data = AUDIT_PIPE_QLIMIT_MAX;
+ error = 0;
+ break;
+
+ case AUDITPIPE_GET_PRESELECT_FLAGS:
+ AUDIT_PIPE_LOCK(ap);
+ maskp = (au_mask_t *)data;
+ *maskp = ap->ap_preselect_flags;
+ AUDIT_PIPE_UNLOCK(ap);
+ error = 0;
+ break;
+
+ case AUDITPIPE_SET_PRESELECT_FLAGS:
+ AUDIT_PIPE_LOCK(ap);
+ maskp = (au_mask_t *)data;
+ ap->ap_preselect_flags = *maskp;
+ AUDIT_PIPE_UNLOCK(ap);
+ error = 0;
+ break;
+
+ case AUDITPIPE_GET_PRESELECT_NAFLAGS:
+ AUDIT_PIPE_LOCK(ap);
+ maskp = (au_mask_t *)data;
+ *maskp = ap->ap_preselect_naflags;
+ AUDIT_PIPE_UNLOCK(ap);
+ error = 0;
+ break;
+
+ case AUDITPIPE_SET_PRESELECT_NAFLAGS:
+ AUDIT_PIPE_LOCK(ap);
+ maskp = (au_mask_t *)data;
+ ap->ap_preselect_naflags = *maskp;
+ AUDIT_PIPE_UNLOCK(ap);
+ error = 0;
+ break;
+
+ case AUDITPIPE_GET_PRESELECT_AUID:
+ aip = (struct auditpipe_ioctl_preselect *)data;
+ error = audit_pipe_preselect_get(ap, aip->aip_auid,
+ &aip->aip_mask);
+ break;
+
+ case AUDITPIPE_SET_PRESELECT_AUID:
+ aip = (struct auditpipe_ioctl_preselect *)data;
+ audit_pipe_preselect_set(ap, aip->aip_auid, aip->aip_mask);
+ error = 0;
+ break;
+
+ case AUDITPIPE_DELETE_PRESELECT_AUID:
+ auid = *(au_id_t *)data;
+ error = audit_pipe_preselect_delete(ap, auid);
+ break;
+
+ case AUDITPIPE_FLUSH_PRESELECT_AUID:
+ audit_pipe_preselect_flush(ap);
+ error = 0;
+ break;
+
+ case AUDITPIPE_GET_PRESELECT_MODE:
+ AUDIT_PIPE_LOCK(ap);
+ *(int *)data = ap->ap_preselect_mode;
+ AUDIT_PIPE_UNLOCK(ap);
+ error = 0;
+ break;
+
+ case AUDITPIPE_SET_PRESELECT_MODE:
+ mode = *(int *)data;
+ switch (mode) {
+ case AUDITPIPE_PRESELECT_MODE_TRAIL:
+ case AUDITPIPE_PRESELECT_MODE_LOCAL:
+ AUDIT_PIPE_LOCK(ap);
+ ap->ap_preselect_mode = mode;
+ AUDIT_PIPE_UNLOCK(ap);
+ error = 0;
+ break;
+
+ default:
+ error = EINVAL;
+ }
+ break;
+
+ case AUDITPIPE_FLUSH:
+ if (AUDIT_PIPE_SX_XLOCK_SIG(ap) != 0)
+ return (EINTR);
+ AUDIT_PIPE_LOCK(ap);
+ audit_pipe_flush(ap);
+ AUDIT_PIPE_UNLOCK(ap);
+ AUDIT_PIPE_SX_XUNLOCK(ap);
+ error = 0;
+ break;
+
+ case AUDITPIPE_GET_MAXAUDITDATA:
+ *(u_int *)data = MAXAUDITDATA;
+ error = 0;
+ break;
+
+ case AUDITPIPE_GET_INSERTS:
+ *(u_int *)data = ap->ap_inserts;
+ error = 0;
+ break;
+
+ case AUDITPIPE_GET_READS:
+ *(u_int *)data = ap->ap_reads;
+ error = 0;
+ break;
+
+ case AUDITPIPE_GET_DROPS:
+ *(u_int *)data = ap->ap_drops;
+ error = 0;
+ break;
+
+ case AUDITPIPE_GET_TRUNCATES:
+ *(u_int *)data = 0;
+ error = 0;
+ break;
+
+ default:
+ error = ENOTTY;
+ }
+ return (error);
+}
+
+/*
+ * Audit pipe read. Read one or more partial or complete records to user
+ * memory.
+ */
+static int
+audit_pipe_read(struct cdev *dev, struct uio *uio, int flag)
+{
+ struct audit_pipe_entry *ape;
+ struct audit_pipe *ap;
+ u_int toread;
+ int error;
+
+ ap = dev->si_drv1;
+ KASSERT(ap != NULL, ("audit_pipe_read: ap == NULL"));
+
+ /*
+ * We hold an sx(9) lock over read and flush because we rely on the
+ * stability of a record in the queue during uiomove(9).
+ */
+ if (AUDIT_PIPE_SX_XLOCK_SIG(ap) != 0)
+ return (EINTR);
+ AUDIT_PIPE_LOCK(ap);
+ while (TAILQ_EMPTY(&ap->ap_queue)) {
+ if (ap->ap_flags & AUDIT_PIPE_NBIO) {
+ AUDIT_PIPE_UNLOCK(ap);
+ AUDIT_PIPE_SX_XUNLOCK(ap);
+ return (EAGAIN);
+ }
+ error = cv_wait_sig(&ap->ap_cv, AUDIT_PIPE_MTX(ap));
+ if (error) {
+ AUDIT_PIPE_UNLOCK(ap);
+ AUDIT_PIPE_SX_XUNLOCK(ap);
+ return (error);
+ }
+ }
+
+ /*
+ * Copy as many remaining bytes from the current record to userspace
+ * as we can. Keep processing records until we run out of records in
+ * the queue, or until the user buffer runs out of space.
+ *
+ * Note: we rely on the SX lock to maintain ape's stability here.
+ */
+ ap->ap_reads++;
+ while ((ape = TAILQ_FIRST(&ap->ap_queue)) != NULL &&
+ uio->uio_resid > 0) {
+ AUDIT_PIPE_LOCK_ASSERT(ap);
+
+ KASSERT(ape->ape_record_len > ap->ap_qoffset,
+ ("audit_pipe_read: record_len > qoffset (1)"));
+ toread = MIN(ape->ape_record_len - ap->ap_qoffset,
+ uio->uio_resid);
+ AUDIT_PIPE_UNLOCK(ap);
+ error = uiomove((char *)ape->ape_record + ap->ap_qoffset,
+ toread, uio);
+ if (error) {
+ AUDIT_PIPE_SX_XUNLOCK(ap);
+ return (error);
+ }
+
+ /*
+ * If the copy succeeded, update book-keeping, and if no
+ * bytes remain in the current record, free it.
+ */
+ AUDIT_PIPE_LOCK(ap);
+ KASSERT(TAILQ_FIRST(&ap->ap_queue) == ape,
+ ("audit_pipe_read: queue out of sync after uiomove"));
+ ap->ap_qoffset += toread;
+ KASSERT(ape->ape_record_len >= ap->ap_qoffset,
+ ("audit_pipe_read: record_len >= qoffset (2)"));
+ if (ap->ap_qoffset == ape->ape_record_len) {
+ TAILQ_REMOVE(&ap->ap_queue, ape, ape_queue);
+ ap->ap_qbyteslen -= ape->ape_record_len;
+ audit_pipe_entry_free(ape);
+ ap->ap_qlen--;
+ ap->ap_qoffset = 0;
+ }
+ }
+ AUDIT_PIPE_UNLOCK(ap);
+ AUDIT_PIPE_SX_XUNLOCK(ap);
+ return (0);
+}
+
+/*
+ * Audit pipe poll.
+ */
+static int
+audit_pipe_poll(struct cdev *dev, int events, struct thread *td)
+{
+ struct audit_pipe *ap;
+ int revents;
+
+ revents = 0;
+ ap = dev->si_drv1;
+ KASSERT(ap != NULL, ("audit_pipe_poll: ap == NULL"));
+
+ if (events & (POLLIN | POLLRDNORM)) {
+ AUDIT_PIPE_LOCK(ap);
+ if (TAILQ_FIRST(&ap->ap_queue) != NULL)
+ revents |= events & (POLLIN | POLLRDNORM);
+ else
+ selrecord(td, &ap->ap_selinfo);
+ AUDIT_PIPE_UNLOCK(ap);
+ }
+ return (revents);
+}
+
+/*
+ * Audit pipe kqfilter.
+ */
+static int
+audit_pipe_kqfilter(struct cdev *dev, struct knote *kn)
+{
+ struct audit_pipe *ap;
+
+ ap = dev->si_drv1;
+ KASSERT(ap != NULL, ("audit_pipe_kqfilter: ap == NULL"));
+
+ if (kn->kn_filter != EVFILT_READ)
+ return (EINVAL);
+
+ kn->kn_fop = &audit_pipe_read_filterops;
+ kn->kn_hook = ap;
+
+ AUDIT_PIPE_LOCK(ap);
+ knlist_add(&ap->ap_selinfo.si_note, kn, 1);
+ AUDIT_PIPE_UNLOCK(ap);
+ return (0);
+}
+
+/*
+ * Return true if there are records available for reading on the pipe.
+ */
+static int
+audit_pipe_kqread(struct knote *kn, long hint)
+{
+ struct audit_pipe_entry *ape;
+ struct audit_pipe *ap;
+
+ ap = (struct audit_pipe *)kn->kn_hook;
+ KASSERT(ap != NULL, ("audit_pipe_kqread: ap == NULL"));
+
+ AUDIT_PIPE_LOCK_ASSERT(ap);
+
+ if (ap->ap_qlen != 0) {
+ ape = TAILQ_FIRST(&ap->ap_queue);
+ KASSERT(ape != NULL, ("audit_pipe_kqread: ape == NULL"));
+
+ kn->kn_data = ap->ap_qbyteslen - ap->ap_qoffset;
+ return (1);
+ } else {
+ kn->kn_data = 0;
+ return (0);
+ }
+}
+
+/*
+ * Detach kqueue state from audit pipe.
+ */
+static void
+audit_pipe_kqdetach(struct knote *kn)
+{
+ struct audit_pipe *ap;
+
+ ap = (struct audit_pipe *)kn->kn_hook;
+ KASSERT(ap != NULL, ("audit_pipe_kqdetach: ap == NULL"));
+
+ AUDIT_PIPE_LOCK(ap);
+ knlist_remove(&ap->ap_selinfo.si_note, kn, 1);
+ AUDIT_PIPE_UNLOCK(ap);
+}
+
+/*
+ * Initialize the audit pipe system.
+ */
+static void
+audit_pipe_init(void *unused)
+{
+
+ TAILQ_INIT(&audit_pipe_list);
+ AUDIT_PIPE_LIST_LOCK_INIT();
+
+ clone_setup(&audit_pipe_clones);
+ audit_pipe_eh_tag = EVENTHANDLER_REGISTER(dev_clone,
+ audit_pipe_clone, 0, 1000);
+ if (audit_pipe_eh_tag == NULL)
+ panic("audit_pipe_init: EVENTHANDLER_REGISTER");
+}
+
+SYSINIT(audit_pipe_init, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, audit_pipe_init,
+ NULL);
diff --git a/sys/security/audit/audit_private.h b/sys/security/audit/audit_private.h
new file mode 100644
index 0000000..b79d966
--- /dev/null
+++ b/sys/security/audit/audit_private.h
@@ -0,0 +1,346 @@
+/*-
+ * Copyright (c) 1999-2005 Apple Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * This include file contains function prototypes and type definitions used
+ * within the audit implementation.
+ */
+
+#ifndef _SECURITY_AUDIT_PRIVATE_H_
+#define _SECURITY_AUDIT_PRIVATE_H_
+
+#ifndef _KERNEL
+#error "no user-serviceable parts inside"
+#endif
+
+#include <sys/ipc.h>
+#include <sys/socket.h>
+#include <sys/ucred.h>
+
+#ifdef MALLOC_DECLARE
+MALLOC_DECLARE(M_AUDITBSM);
+MALLOC_DECLARE(M_AUDITDATA);
+MALLOC_DECLARE(M_AUDITPATH);
+MALLOC_DECLARE(M_AUDITTEXT);
+#endif
+
+/*
+ * Audit control variables that are usually set/read via system calls and
+ * used to control various aspects of auditing.
+ */
+extern struct au_qctrl audit_qctrl;
+extern struct audit_fstat audit_fstat;
+extern struct au_mask audit_nae_mask;
+extern int audit_panic_on_write_fail;
+extern int audit_fail_stop;
+extern int audit_argv;
+extern int audit_arge;
+
+/*
+ * Success/failure conditions for the conversion of a kernel audit record to
+ * BSM format.
+ */
+#define BSM_SUCCESS 0
+#define BSM_FAILURE 1
+#define BSM_NOAUDIT 2
+
+/*
+ * Defines for the kernel audit record k_ar_commit field. Flags are set to
+ * indicate what sort of record it is, and which preselection mechanism
+ * selected it.
+ */
+#define AR_COMMIT_KERNEL 0x00000001U
+#define AR_COMMIT_USER 0x00000010U
+
+#define AR_PRESELECT_TRAIL 0x00001000U
+#define AR_PRESELECT_PIPE 0x00002000U
+
+#define AR_PRESELECT_USER_TRAIL 0x00004000U
+#define AR_PRESELECT_USER_PIPE 0x00008000U
+
+/*
+ * Audit data is generated as a stream of struct audit_record structures,
+ * linked by struct kaudit_record, and contain storage for possible audit so
+ * that it will not need to be allocated during the processing of a system
+ * call, both improving efficiency and avoiding sleeping at untimely moments.
+ * This structure is converted to BSM format before being written to disk.
+ */
+struct vnode_au_info {
+ mode_t vn_mode;
+ uid_t vn_uid;
+ gid_t vn_gid;
+ dev_t vn_dev;
+ long vn_fsid;
+ long vn_fileid;
+ long vn_gen;
+};
+
+struct groupset {
+ gid_t gidset[NGROUPS];
+ u_int gidset_size;
+};
+
+struct socket_au_info {
+ int so_domain;
+ int so_type;
+ int so_protocol;
+ in_addr_t so_raddr; /* Remote address if INET socket. */
+ in_addr_t so_laddr; /* Local address if INET socket. */
+ u_short so_rport; /* Remote port. */
+ u_short so_lport; /* Local port. */
+};
+
+union auditon_udata {
+ char *au_path;
+ long au_cond;
+ long au_flags;
+ long au_policy;
+ int au_trigger;
+ au_evclass_map_t au_evclass;
+ au_mask_t au_mask;
+ auditinfo_t au_auinfo;
+ auditpinfo_t au_aupinfo;
+ auditpinfo_addr_t au_aupinfo_addr;
+ au_qctrl_t au_qctrl;
+ au_stat_t au_stat;
+ au_fstat_t au_fstat;
+ auditinfo_addr_t au_kau_info;
+};
+
+struct posix_ipc_perm {
+ uid_t pipc_uid;
+ gid_t pipc_gid;
+ mode_t pipc_mode;
+};
+
+struct audit_record {
+ /* Audit record header. */
+ u_int32_t ar_magic;
+ int ar_event;
+ int ar_retval; /* value returned to the process */
+ int ar_errno; /* return status of system call */
+ struct timespec ar_starttime;
+ struct timespec ar_endtime;
+ u_int64_t ar_valid_arg; /* Bitmask of valid arguments */
+
+ /* Audit subject information. */
+ struct xucred ar_subj_cred;
+ uid_t ar_subj_ruid;
+ gid_t ar_subj_rgid;
+ gid_t ar_subj_egid;
+ uid_t ar_subj_auid; /* Audit user ID */
+ pid_t ar_subj_asid; /* Audit session ID */
+ pid_t ar_subj_pid;
+ struct au_tid ar_subj_term;
+ struct au_tid_addr ar_subj_term_addr;
+ struct au_mask ar_subj_amask;
+
+ /* Operation arguments. */
+ uid_t ar_arg_euid;
+ uid_t ar_arg_ruid;
+ uid_t ar_arg_suid;
+ gid_t ar_arg_egid;
+ gid_t ar_arg_rgid;
+ gid_t ar_arg_sgid;
+ pid_t ar_arg_pid;
+ pid_t ar_arg_asid;
+ struct au_tid ar_arg_termid;
+ struct au_tid_addr ar_arg_termid_addr;
+ uid_t ar_arg_uid;
+ uid_t ar_arg_auid;
+ gid_t ar_arg_gid;
+ struct groupset ar_arg_groups;
+ int ar_arg_fd;
+ int ar_arg_fflags;
+ mode_t ar_arg_mode;
+ int ar_arg_dev;
+ long ar_arg_value;
+ void * ar_arg_addr;
+ int ar_arg_len;
+ int ar_arg_mask;
+ u_int ar_arg_signum;
+ char ar_arg_login[MAXLOGNAME];
+ int ar_arg_ctlname[CTL_MAXNAME];
+ struct socket_au_info ar_arg_sockinfo;
+ char *ar_arg_upath1;
+ char *ar_arg_upath2;
+ char *ar_arg_text;
+ struct au_mask ar_arg_amask;
+ struct vnode_au_info ar_arg_vnode1;
+ struct vnode_au_info ar_arg_vnode2;
+ int ar_arg_cmd;
+ int ar_arg_svipc_cmd;
+ struct ipc_perm ar_arg_svipc_perm;
+ int ar_arg_svipc_id;
+ void * ar_arg_svipc_addr;
+ struct posix_ipc_perm ar_arg_pipc_perm;
+ union auditon_udata ar_arg_auditon;
+ char *ar_arg_argv;
+ int ar_arg_argc;
+ char *ar_arg_envv;
+ int ar_arg_envc;
+ int ar_arg_exitstatus;
+ int ar_arg_exitretval;
+ struct sockaddr_storage ar_arg_sockaddr;
+};
+
+/*
+ * Arguments in the audit record are initially not defined; flags are set to
+ * indicate if they are present so they can be included in the audit log
+ * stream only if defined.
+ */
+#define ARG_IS_VALID(kar, arg) ((kar)->k_ar.ar_valid_arg & (arg))
+#define ARG_SET_VALID(kar, arg) do { \
+ (kar)->k_ar.ar_valid_arg |= (arg); \
+} while (0)
+
+/*
+ * In-kernel version of audit record; the basic record plus queue meta-data.
+ * This record can also have a pointer set to some opaque data that will be
+ * passed through to the audit writing mechanism.
+ */
+struct kaudit_record {
+ struct audit_record k_ar;
+ u_int32_t k_ar_commit;
+ void *k_udata; /* User data. */
+ u_int k_ulen; /* User data length. */
+ struct uthread *k_uthread; /* Audited thread. */
+ TAILQ_ENTRY(kaudit_record) k_q;
+};
+TAILQ_HEAD(kaudit_queue, kaudit_record);
+
+/*
+ * Functions to manage the allocation, release, and commit of kernel audit
+ * records.
+ */
+void audit_abort(struct kaudit_record *ar);
+void audit_commit(struct kaudit_record *ar, int error,
+ int retval);
+struct kaudit_record *audit_new(int event, struct thread *td);
+
+/*
+ * Functions relating to the conversion of internal kernel audit records to
+ * the BSM file format.
+ */
+struct au_record;
+int kaudit_to_bsm(struct kaudit_record *kar, struct au_record **pau);
+int bsm_rec_verify(void *rec);
+
+/*
+ * Kernel versions of the libbsm audit record functions.
+ */
+void kau_free(struct au_record *rec);
+void kau_init(void);
+
+/*
+ * Return values for pre-selection and post-selection decisions.
+ */
+#define AU_PRS_SUCCESS 1
+#define AU_PRS_FAILURE 2
+#define AU_PRS_BOTH (AU_PRS_SUCCESS|AU_PRS_FAILURE)
+
+/*
+ * Data structures relating to the kernel audit queue. Ideally, these might
+ * be abstracted so that only accessor methods are exposed.
+ */
+extern struct mtx audit_mtx;
+extern struct cv audit_watermark_cv;
+extern struct cv audit_worker_cv;
+extern struct kaudit_queue audit_q;
+extern size_t audit_q_len;
+extern size_t audit_pre_q_len;
+extern int audit_in_failure;
+
+/*
+ * Flags to use on audit files when opening and closing.
+ */
+#define AUDIT_OPEN_FLAGS (FWRITE | O_APPEND)
+#define AUDIT_CLOSE_FLAGS (FWRITE | O_APPEND)
+
+#include <sys/fcntl.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+
+/*
+ * Some of the BSM tokenizer functions take different parameters in the
+ * kernel implementations in order to save the copying of large kernel data
+ * structures. The prototypes of these functions are declared here.
+ */
+token_t *kau_to_socket(struct socket_au_info *soi);
+
+/*
+ * audit_klib prototypes
+ */
+int au_preselect(au_event_t event, au_class_t class,
+ au_mask_t *mask_p, int sorf);
+void au_evclassmap_init(void);
+void au_evclassmap_insert(au_event_t event, au_class_t class);
+au_class_t au_event_class(au_event_t event);
+au_event_t audit_ctlname_to_sysctlevent(int name[], uint64_t valid_arg);
+au_event_t audit_flags_and_error_to_openevent(int oflags, int error);
+int audit_msgctl_to_event(int cmd);
+int audit_semctl_to_event(int cmr);
+void audit_canon_path(struct thread *td, char *path, char *cpath);
+int auditon_command_event(int cmd);
+
+/*
+ * Audit trigger events notify user space of kernel audit conditions
+ * asynchronously.
+ */
+void audit_trigger_init(void);
+int audit_send_trigger(unsigned int trigger);
+
+/*
+ * Accessor functions to manage global audit state.
+ */
+void audit_set_kinfo(struct auditinfo_addr *);
+void audit_get_kinfo(struct auditinfo_addr *);
+
+/*
+ * General audit related functions.
+ */
+struct kaudit_record *currecord(void);
+void audit_free(struct kaudit_record *ar);
+void audit_shutdown(void *arg, int howto);
+void audit_rotate_vnode(struct ucred *cred,
+ struct vnode *vp);
+void audit_worker_init(void);
+
+/*
+ * Audit pipe functions.
+ */
+int audit_pipe_preselect(au_id_t auid, au_event_t event,
+ au_class_t class, int sorf, int trail_select);
+void audit_pipe_submit(au_id_t auid, au_event_t event, au_class_t class,
+ int sorf, int trail_select, void *record, u_int record_len);
+void audit_pipe_submit_user(void *record, u_int record_len);
+
+#endif /* ! _SECURITY_AUDIT_PRIVATE_H_ */
diff --git a/sys/security/audit/audit_syscalls.c b/sys/security/audit/audit_syscalls.c
new file mode 100644
index 0000000..f8d45fe
--- /dev/null
+++ b/sys/security/audit/audit_syscalls.c
@@ -0,0 +1,759 @@
+/*-
+ * Copyright (c) 1999-2005 Apple Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "opt_mac.h"
+
+#include <sys/param.h>
+#include <sys/mount.h>
+#include <sys/namei.h>
+#include <sys/priv.h>
+#include <sys/proc.h>
+#include <sys/sysproto.h>
+#include <sys/systm.h>
+#include <sys/vnode.h>
+#include <sys/jail.h>
+
+#include <bsm/audit.h>
+#include <bsm/audit_kevents.h>
+
+#include <security/audit/audit.h>
+#include <security/audit/audit_private.h>
+#include <security/mac/mac_framework.h>
+
+#ifdef AUDIT
+
+/*
+ * System call to allow a user space application to submit a BSM audit record
+ * to the kernel for inclusion in the audit log. This function does little
+ * verification on the audit record that is submitted.
+ *
+ * XXXAUDIT: Audit preselection for user records does not currently work,
+ * since we pre-select only based on the AUE_audit event type, not the event
+ * type submitted as part of the user audit data.
+ */
+/* ARGSUSED */
+int
+audit(struct thread *td, struct audit_args *uap)
+{
+ int error;
+ void * rec;
+ struct kaudit_record *ar;
+
+ if (jailed(td->td_ucred))
+ return (ENOSYS);
+ error = priv_check(td, PRIV_AUDIT_SUBMIT);
+ if (error)
+ return (error);
+
+ if ((uap->length <= 0) || (uap->length > audit_qctrl.aq_bufsz))
+ return (EINVAL);
+
+ ar = currecord();
+
+ /*
+ * If there's no current audit record (audit() itself not audited)
+ * commit the user audit record.
+ */
+ if (ar == NULL) {
+
+ /*
+ * This is not very efficient; we're required to allocate a
+ * complete kernel audit record just so the user record can
+ * tag along.
+ *
+ * XXXAUDIT: Maybe AUE_AUDIT in the system call context and
+ * special pre-select handling?
+ */
+ td->td_ar = audit_new(AUE_NULL, td);
+ if (td->td_ar == NULL)
+ return (ENOTSUP);
+ ar = td->td_ar;
+ }
+
+ if (uap->length > MAX_AUDIT_RECORD_SIZE)
+ return (EINVAL);
+
+ rec = malloc(uap->length, M_AUDITDATA, M_WAITOK);
+
+ error = copyin(uap->record, rec, uap->length);
+ if (error)
+ goto free_out;
+
+ /* Verify the record. */
+ if (bsm_rec_verify(rec) == 0) {
+ error = EINVAL;
+ goto free_out;
+ }
+
+#ifdef MAC
+ error = mac_system_check_audit(td->td_ucred, rec, uap->length);
+ if (error)
+ goto free_out;
+#endif
+
+ /*
+ * Attach the user audit record to the kernel audit record. Because
+ * this system call is an auditable event, we will write the user
+ * record along with the record for this audit event.
+ *
+ * XXXAUDIT: KASSERT appropriate starting values of k_udata, k_ulen,
+ * k_ar_commit & AR_COMMIT_USER?
+ */
+ ar->k_udata = rec;
+ ar->k_ulen = uap->length;
+ ar->k_ar_commit |= AR_COMMIT_USER;
+
+ /*
+ * Currently we assume that all preselection has been performed in
+ * userspace. We unconditionally set these masks so that the records
+ * get committed both to the trail and pipe. In the future we will
+ * want to setup kernel based preselection.
+ */
+ ar->k_ar_commit |= (AR_PRESELECT_USER_TRAIL | AR_PRESELECT_USER_PIPE);
+ return (0);
+
+free_out:
+ /*
+ * audit_syscall_exit() will free the audit record on the thread even
+ * if we allocated it above.
+ */
+ free(rec, M_AUDITDATA);
+ return (error);
+}
+
+/*
+ * System call to manipulate auditing.
+ */
+/* ARGSUSED */
+int
+auditon(struct thread *td, struct auditon_args *uap)
+{
+ struct ucred *cred, *newcred, *oldcred;
+ int error;
+ union auditon_udata udata;
+ struct proc *tp;
+
+ if (jailed(td->td_ucred))
+ return (ENOSYS);
+ AUDIT_ARG(cmd, uap->cmd);
+
+#ifdef MAC
+ error = mac_system_check_auditon(td->td_ucred, uap->cmd);
+ if (error)
+ return (error);
+#endif
+
+ error = priv_check(td, PRIV_AUDIT_CONTROL);
+ if (error)
+ return (error);
+
+ if ((uap->length <= 0) || (uap->length > sizeof(union auditon_udata)))
+ return (EINVAL);
+
+ memset((void *)&udata, 0, sizeof(udata));
+
+ /*
+ * Some of the GET commands use the arguments too.
+ */
+ switch (uap->cmd) {
+ case A_SETPOLICY:
+ case A_SETKMASK:
+ case A_SETQCTRL:
+ case A_SETSTAT:
+ case A_SETUMASK:
+ case A_SETSMASK:
+ case A_SETCOND:
+ case A_SETCLASS:
+ case A_SETPMASK:
+ case A_SETFSIZE:
+ case A_SETKAUDIT:
+ case A_GETCLASS:
+ case A_GETPINFO:
+ case A_GETPINFO_ADDR:
+ case A_SENDTRIGGER:
+ error = copyin(uap->data, (void *)&udata, uap->length);
+ if (error)
+ return (error);
+ AUDIT_ARG(auditon, &udata);
+ break;
+ }
+
+ /*
+ * XXXAUDIT: Locking?
+ */
+ switch (uap->cmd) {
+ case A_GETPOLICY:
+ if (!audit_fail_stop)
+ udata.au_policy |= AUDIT_CNT;
+ if (audit_panic_on_write_fail)
+ udata.au_policy |= AUDIT_AHLT;
+ if (audit_argv)
+ udata.au_policy |= AUDIT_ARGV;
+ if (audit_arge)
+ udata.au_policy |= AUDIT_ARGE;
+ break;
+
+ case A_SETPOLICY:
+ if (udata.au_policy & ~(AUDIT_CNT|AUDIT_AHLT|AUDIT_ARGV|
+ AUDIT_ARGE))
+ return (EINVAL);
+ /*
+ * XXX - Need to wake up waiters if the policy relaxes?
+ */
+ audit_fail_stop = ((udata.au_policy & AUDIT_CNT) == 0);
+ audit_panic_on_write_fail = (udata.au_policy & AUDIT_AHLT);
+ audit_argv = (udata.au_policy & AUDIT_ARGV);
+ audit_arge = (udata.au_policy & AUDIT_ARGE);
+ break;
+
+ case A_GETKMASK:
+ udata.au_mask = audit_nae_mask;
+ break;
+
+ case A_SETKMASK:
+ audit_nae_mask = udata.au_mask;
+ break;
+
+ case A_GETQCTRL:
+ udata.au_qctrl = audit_qctrl;
+ break;
+
+ case A_SETQCTRL:
+ if ((udata.au_qctrl.aq_hiwater > AQ_MAXHIGH) ||
+ (udata.au_qctrl.aq_lowater >= udata.au_qctrl.aq_hiwater) ||
+ (udata.au_qctrl.aq_bufsz > AQ_MAXBUFSZ) ||
+ (udata.au_qctrl.aq_minfree < 0) ||
+ (udata.au_qctrl.aq_minfree > 100))
+ return (EINVAL);
+
+ audit_qctrl = udata.au_qctrl;
+ /* XXX The queue delay value isn't used with the kernel. */
+ audit_qctrl.aq_delay = -1;
+ break;
+
+ case A_GETCWD:
+ return (ENOSYS);
+ break;
+
+ case A_GETCAR:
+ return (ENOSYS);
+ break;
+
+ case A_GETSTAT:
+ return (ENOSYS);
+ break;
+
+ case A_SETSTAT:
+ return (ENOSYS);
+ break;
+
+ case A_SETUMASK:
+ return (ENOSYS);
+ break;
+
+ case A_SETSMASK:
+ return (ENOSYS);
+ break;
+
+ case A_GETCOND:
+ if (audit_enabled && !audit_suspended)
+ udata.au_cond = AUC_AUDITING;
+ else
+ udata.au_cond = AUC_NOAUDIT;
+ break;
+
+ case A_SETCOND:
+ if (udata.au_cond == AUC_NOAUDIT)
+ audit_suspended = 1;
+ if (udata.au_cond == AUC_AUDITING)
+ audit_suspended = 0;
+ if (udata.au_cond == AUC_DISABLED) {
+ audit_suspended = 1;
+ audit_shutdown(NULL, 0);
+ }
+ break;
+
+ case A_GETCLASS:
+ udata.au_evclass.ec_class = au_event_class(
+ udata.au_evclass.ec_number);
+ break;
+
+ case A_SETCLASS:
+ au_evclassmap_insert(udata.au_evclass.ec_number,
+ udata.au_evclass.ec_class);
+ break;
+
+ case A_GETPINFO:
+ if (udata.au_aupinfo.ap_pid < 1)
+ return (ESRCH);
+ if ((tp = pfind(udata.au_aupinfo.ap_pid)) == NULL)
+ return (ESRCH);
+ if ((error = p_cansee(td, tp)) != 0) {
+ PROC_UNLOCK(tp);
+ return (error);
+ }
+ cred = tp->p_ucred;
+ if (cred->cr_audit.ai_termid.at_type == AU_IPv6) {
+ PROC_UNLOCK(tp);
+ return (EINVAL);
+ }
+ udata.au_aupinfo.ap_auid = cred->cr_audit.ai_auid;
+ udata.au_aupinfo.ap_mask.am_success =
+ cred->cr_audit.ai_mask.am_success;
+ udata.au_aupinfo.ap_mask.am_failure =
+ cred->cr_audit.ai_mask.am_failure;
+ udata.au_aupinfo.ap_termid.machine =
+ cred->cr_audit.ai_termid.at_addr[0];
+ udata.au_aupinfo.ap_termid.port =
+ (dev_t)cred->cr_audit.ai_termid.at_port;
+ udata.au_aupinfo.ap_asid = cred->cr_audit.ai_asid;
+ PROC_UNLOCK(tp);
+ break;
+
+ case A_SETPMASK:
+ if (udata.au_aupinfo.ap_pid < 1)
+ return (ESRCH);
+ newcred = crget();
+ if ((tp = pfind(udata.au_aupinfo.ap_pid)) == NULL) {
+ crfree(newcred);
+ return (ESRCH);
+ }
+ if ((error = p_cansee(td, tp)) != 0) {
+ PROC_UNLOCK(tp);
+ crfree(newcred);
+ return (error);
+ }
+ oldcred = tp->p_ucred;
+ crcopy(newcred, oldcred);
+ newcred->cr_audit.ai_mask.am_success =
+ udata.au_aupinfo.ap_mask.am_success;
+ 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:
+ if ((udata.au_fstat.af_filesz != 0) &&
+ (udata.au_fstat.af_filesz < MIN_AUDIT_FILE_SIZE))
+ return (EINVAL);
+ audit_fstat.af_filesz = udata.au_fstat.af_filesz;
+ break;
+
+ case A_GETFSIZE:
+ udata.au_fstat.af_filesz = audit_fstat.af_filesz;
+ udata.au_fstat.af_currsz = audit_fstat.af_currsz;
+ break;
+
+ case A_GETPINFO_ADDR:
+ if (udata.au_aupinfo_addr.ap_pid < 1)
+ return (ESRCH);
+ if ((tp = pfind(udata.au_aupinfo_addr.ap_pid)) == NULL)
+ return (ESRCH);
+ cred = tp->p_ucred;
+ udata.au_aupinfo_addr.ap_auid = cred->cr_audit.ai_auid;
+ udata.au_aupinfo_addr.ap_mask.am_success =
+ cred->cr_audit.ai_mask.am_success;
+ udata.au_aupinfo_addr.ap_mask.am_failure =
+ cred->cr_audit.ai_mask.am_failure;
+ udata.au_aupinfo_addr.ap_termid = cred->cr_audit.ai_termid;
+ udata.au_aupinfo_addr.ap_asid = cred->cr_audit.ai_asid;
+ PROC_UNLOCK(tp);
+ break;
+
+ case A_GETKAUDIT:
+ audit_get_kinfo(&udata.au_kau_info);
+ break;
+
+ case A_SETKAUDIT:
+ if (udata.au_kau_info.ai_termid.at_type != AU_IPv4 &&
+ udata.au_kau_info.ai_termid.at_type != AU_IPv6)
+ return (EINVAL);
+ audit_set_kinfo(&udata.au_kau_info);
+ break;
+
+ case A_SENDTRIGGER:
+ if ((udata.au_trigger < AUDIT_TRIGGER_MIN) ||
+ (udata.au_trigger > AUDIT_TRIGGER_MAX))
+ return (EINVAL);
+ return (audit_send_trigger(udata.au_trigger));
+
+ default:
+ return (EINVAL);
+ }
+
+ /*
+ * Copy data back to userspace for the GET comands.
+ */
+ switch (uap->cmd) {
+ case A_GETPOLICY:
+ case A_GETKMASK:
+ case A_GETQCTRL:
+ case A_GETCWD:
+ case A_GETCAR:
+ case A_GETSTAT:
+ case A_GETCOND:
+ case A_GETCLASS:
+ case A_GETPINFO:
+ case A_GETFSIZE:
+ case A_GETPINFO_ADDR:
+ case A_GETKAUDIT:
+ error = copyout((void *)&udata, uap->data, uap->length);
+ if (error)
+ return (error);
+ break;
+ }
+
+ return (0);
+}
+
+/*
+ * System calls to manage the user audit information.
+ */
+/* ARGSUSED */
+int
+getauid(struct thread *td, struct getauid_args *uap)
+{
+ int error;
+
+ if (jailed(td->td_ucred))
+ return (ENOSYS);
+ error = priv_check(td, PRIV_AUDIT_GETAUDIT);
+ if (error)
+ return (error);
+ 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)
+{
+ struct ucred *newcred, *oldcred;
+ au_id_t id;
+ int error;
+
+ if (jailed(td->td_ucred))
+ return (ENOSYS);
+ error = copyin(uap->auid, &id, sizeof(id));
+ if (error)
+ return (error);
+ audit_arg_auid(id);
+ newcred = crget();
+ PROC_LOCK(td->td_proc);
+ oldcred = td->td_proc->p_ucred;
+ crcopy(newcred, oldcred);
+#ifdef MAC
+ error = mac_proc_check_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);
+}
+
+/*
+ * System calls to get and set process audit information.
+ */
+/* ARGSUSED */
+int
+getaudit(struct thread *td, struct getaudit_args *uap)
+{
+ struct auditinfo ai;
+ struct ucred *cred;
+ int error;
+
+ cred = td->td_ucred;
+ if (jailed(cred))
+ return (ENOSYS);
+ error = priv_check(td, PRIV_AUDIT_GETAUDIT);
+ if (error)
+ return (error);
+ if (cred->cr_audit.ai_termid.at_type == AU_IPv6)
+ return (E2BIG);
+ bzero(&ai, sizeof(ai));
+ ai.ai_auid = cred->cr_audit.ai_auid;
+ ai.ai_mask = cred->cr_audit.ai_mask;
+ ai.ai_asid = cred->cr_audit.ai_asid;
+ ai.ai_termid.machine = cred->cr_audit.ai_termid.at_addr[0];
+ ai.ai_termid.port = cred->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 = copyin(uap->auditinfo, &ai, sizeof(ai));
+ if (error)
+ return (error);
+ audit_arg_auditinfo(&ai);
+ newcred = crget();
+ PROC_LOCK(td->td_proc);
+ oldcred = td->td_proc->p_ucred;
+ crcopy(newcred, oldcred);
+#ifdef MAC
+ error = mac_proc_check_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)
+{
+ 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);
+ 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 = copyin(uap->auditinfo_addr, &aia, sizeof(aia));
+ if (error)
+ return (error);
+ audit_arg_auditinfo_addr(&aia);
+ if (aia.ai_termid.at_type != AU_IPv6 &&
+ aia.ai_termid.at_type != AU_IPv4)
+ return (EINVAL);
+ newcred = crget();
+ PROC_LOCK(td->td_proc);
+ oldcred = td->td_proc->p_ucred;
+ crcopy(newcred, oldcred);
+#ifdef MAC
+ error = mac_proc_check_setaudit_addr(oldcred, &aia);
+ 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:
+ PROC_UNLOCK(td->td_proc);
+ crfree(newcred);
+ return (error);
+}
+
+/*
+ * Syscall to manage audit files.
+ */
+/* ARGSUSED */
+int
+auditctl(struct thread *td, struct auditctl_args *uap)
+{
+ struct nameidata nd;
+ struct ucred *cred;
+ struct vnode *vp;
+ int error = 0;
+ int flags, vfslocked;
+
+ if (jailed(td->td_ucred))
+ return (ENOSYS);
+ error = priv_check(td, PRIV_AUDIT_CONTROL);
+ if (error)
+ return (error);
+
+ vp = NULL;
+ cred = NULL;
+
+ /*
+ * If a path is specified, open the replacement vnode, perform
+ * validity checks, and grab another reference to the current
+ * credential.
+ *
+ * On Darwin, a NULL path argument is also used to disable audit.
+ */
+ if (uap->path == NULL)
+ return (EINVAL);
+
+ NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | MPSAFE | AUDITVNODE1,
+ UIO_USERSPACE, uap->path, td);
+ flags = AUDIT_OPEN_FLAGS;
+ error = vn_open(&nd, &flags, 0, NULL);
+ if (error)
+ return (error);
+ vfslocked = NDHASGIANT(&nd);
+ vp = nd.ni_vp;
+#ifdef MAC
+ error = mac_system_check_auditctl(td->td_ucred, vp);
+ VOP_UNLOCK(vp, 0);
+ if (error) {
+ vn_close(vp, AUDIT_CLOSE_FLAGS, td->td_ucred, td);
+ VFS_UNLOCK_GIANT(vfslocked);
+ return (error);
+ }
+#else
+ VOP_UNLOCK(vp, 0);
+#endif
+ NDFREE(&nd, NDF_ONLY_PNBUF);
+ if (vp->v_type != VREG) {
+ vn_close(vp, AUDIT_CLOSE_FLAGS, td->td_ucred, td);
+ VFS_UNLOCK_GIANT(vfslocked);
+ return (EINVAL);
+ }
+ VFS_UNLOCK_GIANT(vfslocked);
+ cred = td->td_ucred;
+ crhold(cred);
+
+ /*
+ * XXXAUDIT: Should audit_suspended actually be cleared by
+ * audit_worker?
+ */
+ audit_suspended = 0;
+
+ audit_rotate_vnode(cred, vp);
+
+ return (error);
+}
+
+#else /* !AUDIT */
+
+int
+audit(struct thread *td, struct audit_args *uap)
+{
+
+ return (ENOSYS);
+}
+
+int
+auditon(struct thread *td, struct auditon_args *uap)
+{
+
+ return (ENOSYS);
+}
+
+int
+getauid(struct thread *td, struct getauid_args *uap)
+{
+
+ return (ENOSYS);
+}
+
+int
+setauid(struct thread *td, struct setauid_args *uap)
+{
+
+ return (ENOSYS);
+}
+
+int
+getaudit(struct thread *td, struct getaudit_args *uap)
+{
+
+ return (ENOSYS);
+}
+
+int
+setaudit(struct thread *td, struct setaudit_args *uap)
+{
+
+ return (ENOSYS);
+}
+
+int
+getaudit_addr(struct thread *td, struct getaudit_addr_args *uap)
+{
+
+ return (ENOSYS);
+}
+
+int
+setaudit_addr(struct thread *td, struct setaudit_addr_args *uap)
+{
+
+ return (ENOSYS);
+}
+
+int
+auditctl(struct thread *td, struct auditctl_args *uap)
+{
+
+ return (ENOSYS);
+}
+#endif /* AUDIT */
diff --git a/sys/security/audit/audit_trigger.c b/sys/security/audit/audit_trigger.c
new file mode 100644
index 0000000..7eb7899
--- /dev/null
+++ b/sys/security/audit/audit_trigger.c
@@ -0,0 +1,178 @@
+/*-
+ * Copyright (c) 2005 Wayne J. Salamon
+ * All rights reserved.
+ *
+ * This software was developed by Wayne Salamon for the TrustedBSD Project.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/conf.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/proc.h>
+#include <sys/queue.h>
+#include <sys/systm.h>
+#include <sys/uio.h>
+
+#include <security/audit/audit.h>
+#include <security/audit/audit_private.h>
+
+/*
+ * Structures and operations to support the basic character special device
+ * used to communicate with userland. /dev/audit reliably delivers one-byte
+ * messages to a listening application (or discards them if there is no
+ * listening application).
+ *
+ * Currently, select/poll are not supported on the trigger device.
+ */
+struct trigger_info {
+ unsigned int trigger;
+ TAILQ_ENTRY(trigger_info) list;
+};
+
+static MALLOC_DEFINE(M_AUDITTRIGGER, "audit_trigger", "Audit trigger events");
+static struct cdev *audit_dev;
+static int audit_isopen = 0;
+static TAILQ_HEAD(, trigger_info) trigger_list;
+static struct mtx audit_trigger_mtx;
+
+static int
+audit_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
+{
+ int error;
+
+ /* Only one process may open the device at a time. */
+ mtx_lock(&audit_trigger_mtx);
+ if (!audit_isopen) {
+ error = 0;
+ audit_isopen = 1;
+ } else
+ error = EBUSY;
+ mtx_unlock(&audit_trigger_mtx);
+
+ return (error);
+}
+
+static int
+audit_close(struct cdev *dev, int fflag, int devtype, struct thread *td)
+{
+ struct trigger_info *ti;
+
+ /* Flush the queue of pending trigger events. */
+ mtx_lock(&audit_trigger_mtx);
+ audit_isopen = 0;
+ while (!TAILQ_EMPTY(&trigger_list)) {
+ ti = TAILQ_FIRST(&trigger_list);
+ TAILQ_REMOVE(&trigger_list, ti, list);
+ free(ti, M_AUDITTRIGGER);
+ }
+ mtx_unlock(&audit_trigger_mtx);
+
+ return (0);
+}
+
+static int
+audit_read(struct cdev *dev, struct uio *uio, int ioflag)
+{
+ int error = 0;
+ struct trigger_info *ti = NULL;
+
+ mtx_lock(&audit_trigger_mtx);
+ while (TAILQ_EMPTY(&trigger_list)) {
+ error = msleep(&trigger_list, &audit_trigger_mtx,
+ PSOCK | PCATCH, "auditd", 0);
+ if (error)
+ break;
+ }
+ if (!error) {
+ ti = TAILQ_FIRST(&trigger_list);
+ TAILQ_REMOVE(&trigger_list, ti, list);
+ }
+ mtx_unlock(&audit_trigger_mtx);
+ if (!error) {
+ error = uiomove(&ti->trigger, sizeof(ti->trigger), uio);
+ free(ti, M_AUDITTRIGGER);
+ }
+ return (error);
+}
+
+static int
+audit_write(struct cdev *dev, struct uio *uio, int ioflag)
+{
+
+ /* Communication is kernel->userspace only. */
+ return (EOPNOTSUPP);
+}
+
+int
+audit_send_trigger(unsigned int trigger)
+{
+ struct trigger_info *ti;
+
+ ti = malloc(sizeof *ti, M_AUDITTRIGGER, M_WAITOK);
+ mtx_lock(&audit_trigger_mtx);
+ if (!audit_isopen) {
+ /* If nobody's listening, we ain't talking. */
+ mtx_unlock(&audit_trigger_mtx);
+ free(ti, M_AUDITTRIGGER);
+ return (ENODEV);
+ }
+ ti->trigger = trigger;
+ TAILQ_INSERT_TAIL(&trigger_list, ti, list);
+ wakeup(&trigger_list);
+ mtx_unlock(&audit_trigger_mtx);
+ return (0);
+}
+
+static struct cdevsw audit_cdevsw = {
+ .d_version = D_VERSION,
+ .d_open = audit_open,
+ .d_close = audit_close,
+ .d_read = audit_read,
+ .d_write = audit_write,
+ .d_name = "audit"
+};
+
+void
+audit_trigger_init(void)
+{
+
+ TAILQ_INIT(&trigger_list);
+ mtx_init(&audit_trigger_mtx, "audit_trigger_mtx", NULL, MTX_DEF);
+}
+
+static void
+audit_trigger_cdev_init(void *unused)
+{
+
+ /* Create the special device file. */
+ audit_dev = make_dev(&audit_cdevsw, 0, UID_ROOT, GID_KMEM, 0600,
+ AUDITDEV_FILENAME);
+}
+
+SYSINIT(audit_trigger_cdev_init, SI_SUB_DRIVERS, SI_ORDER_MIDDLE,
+ audit_trigger_cdev_init, NULL);
diff --git a/sys/security/audit/audit_worker.c b/sys/security/audit/audit_worker.c
new file mode 100644
index 0000000..191d583
--- /dev/null
+++ b/sys/security/audit/audit_worker.c
@@ -0,0 +1,494 @@
+/*-
+ * Copyright (c) 1999-2008 Apple Inc.
+ * Copyright (c) 2006-2008 Robert N. M. Watson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/condvar.h>
+#include <sys/conf.h>
+#include <sys/file.h>
+#include <sys/filedesc.h>
+#include <sys/fcntl.h>
+#include <sys/ipc.h>
+#include <sys/kernel.h>
+#include <sys/kthread.h>
+#include <sys/malloc.h>
+#include <sys/mount.h>
+#include <sys/namei.h>
+#include <sys/proc.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/protosw.h>
+#include <sys/domain.h>
+#include <sys/sx.h>
+#include <sys/sysproto.h>
+#include <sys/sysent.h>
+#include <sys/systm.h>
+#include <sys/ucred.h>
+#include <sys/uio.h>
+#include <sys/un.h>
+#include <sys/unistd.h>
+#include <sys/vnode.h>
+
+#include <bsm/audit.h>
+#include <bsm/audit_internal.h>
+#include <bsm/audit_kevents.h>
+
+#include <netinet/in.h>
+#include <netinet/in_pcb.h>
+
+#include <security/audit/audit.h>
+#include <security/audit/audit_private.h>
+
+#include <vm/uma.h>
+
+/*
+ * Worker thread that will schedule disk I/O, etc.
+ */
+static struct proc *audit_thread;
+
+/*
+ * audit_cred and audit_vp are the stored credential and vnode to use for
+ * active audit trail. They are protected by the audit worker lock, which
+ * will be held across all I/O and all rotation to prevent them from being
+ * replaced (rotated) while in use. The audit_file_rotate_wait flag is set
+ * when the kernel has delivered a trigger to auditd to rotate the trail, and
+ * is cleared when the next rotation takes place. It is also protected by
+ * the audit worker lock.
+ */
+static int audit_file_rotate_wait;
+static struct ucred *audit_cred;
+static struct vnode *audit_vp;
+static struct sx audit_worker_lock;
+
+#define AUDIT_WORKER_LOCK_INIT() sx_init(&audit_worker_lock, \
+ "audit_worker_lock");
+#define AUDIT_WORKER_LOCK_ASSERT() sx_assert(&audit_worker_lock, \
+ SA_XLOCKED)
+#define AUDIT_WORKER_LOCK() sx_xlock(&audit_worker_lock)
+#define AUDIT_WORKER_UNLOCK() sx_xunlock(&audit_worker_lock)
+
+/*
+ * Write an audit record to a file, performed as the last stage after both
+ * preselection and BSM conversion. Both space management and write failures
+ * are handled in this function.
+ *
+ * No attempt is made to deal with possible failure to deliver a trigger to
+ * the audit daemon, since the message is asynchronous anyway.
+ */
+static void
+audit_record_write(struct vnode *vp, struct ucred *cred, void *data,
+ size_t len)
+{
+ static struct timeval last_lowspace_trigger;
+ static struct timeval last_fail;
+ static int cur_lowspace_trigger;
+ struct statfs *mnt_stat;
+ int error, vfslocked;
+ static int cur_fail;
+ struct vattr vattr;
+ long temp;
+
+ AUDIT_WORKER_LOCK_ASSERT();
+
+ if (vp == NULL)
+ return;
+
+ mnt_stat = &vp->v_mount->mnt_stat;
+ vfslocked = VFS_LOCK_GIANT(vp->v_mount);
+
+ /*
+ * First, gather statistics on the audit log file and file system so
+ * that we know how we're doing on space. Consider failure of these
+ * operations to indicate a future inability to write to the file.
+ */
+ error = VFS_STATFS(vp->v_mount, mnt_stat, curthread);
+ if (error)
+ goto fail;
+ vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
+ error = VOP_GETATTR(vp, &vattr, cred);
+ VOP_UNLOCK(vp, 0);
+ if (error)
+ goto fail;
+ audit_fstat.af_currsz = vattr.va_size;
+
+ /*
+ * We handle four different space-related limits:
+ *
+ * - A fixed (hard) limit on the minimum free blocks we require on
+ * the file system, and results in record loss, a trigger, and
+ * possible fail stop due to violating invariants.
+ *
+ * - An administrative (soft) limit, which when fallen below, results
+ * in the kernel notifying the audit daemon of low space.
+ *
+ * - An audit trail size limit, which when gone above, results in the
+ * kernel notifying the audit daemon that rotation is desired.
+ *
+ * - The total depth of the kernel audit record exceeding free space,
+ * which can lead to possible fail stop (with drain), in order to
+ * prevent violating invariants. Failure here doesn't halt
+ * immediately, but prevents new records from being generated.
+ *
+ * Possibly, the last of these should be handled differently, always
+ * allowing a full queue to be lost, rather than trying to prevent
+ * loss.
+ *
+ * First, handle the hard limit, which generates a trigger and may
+ * fail stop. This is handled in the same manner as ENOSPC from
+ * VOP_WRITE, and results in record loss.
+ */
+ if (mnt_stat->f_bfree < AUDIT_HARD_LIMIT_FREE_BLOCKS) {
+ error = ENOSPC;
+ goto fail_enospc;
+ }
+
+ /*
+ * Second, handle falling below the soft limit, if defined; we send
+ * the daemon a trigger and continue processing the record. Triggers
+ * are limited to 1/sec.
+ */
+ if (audit_qctrl.aq_minfree != 0) {
+ temp = mnt_stat->f_blocks / (100 / audit_qctrl.aq_minfree);
+ if (mnt_stat->f_bfree < temp) {
+ if (ppsratecheck(&last_lowspace_trigger,
+ &cur_lowspace_trigger, 1)) {
+ (void)audit_send_trigger(
+ AUDIT_TRIGGER_LOW_SPACE);
+ printf("Warning: disk space low (< %d%% free) "
+ "on audit log file-system\n",
+ audit_qctrl.aq_minfree);
+ }
+ }
+ }
+
+ /*
+ * If the current file is getting full, generate a rotation trigger
+ * to the daemon. This is only approximate, which is fine as more
+ * records may be generated before the daemon rotates the file.
+ */
+ if ((audit_fstat.af_filesz != 0) && (audit_file_rotate_wait == 0) &&
+ (vattr.va_size >= audit_fstat.af_filesz)) {
+ AUDIT_WORKER_LOCK_ASSERT();
+
+ audit_file_rotate_wait = 1;
+ (void)audit_send_trigger(AUDIT_TRIGGER_ROTATE_KERNEL);
+ }
+
+ /*
+ * If the estimated amount of audit data in the audit event queue
+ * (plus records allocated but not yet queued) has reached the amount
+ * of free space on the disk, then we need to go into an audit fail
+ * stop state, in which we do not permit the allocation/committing of
+ * any new audit records. We continue to process records but don't
+ * allow any activities that might generate new records. In the
+ * future, we might want to detect when space is available again and
+ * allow operation to continue, but this behavior is sufficient to
+ * meet fail stop requirements in CAPP.
+ */
+ if (audit_fail_stop) {
+ if ((unsigned long)((audit_q_len + audit_pre_q_len + 1) *
+ MAX_AUDIT_RECORD_SIZE) / mnt_stat->f_bsize >=
+ (unsigned long)(mnt_stat->f_bfree)) {
+ if (ppsratecheck(&last_fail, &cur_fail, 1))
+ printf("audit_record_write: free space "
+ "below size of audit queue, failing "
+ "stop\n");
+ audit_in_failure = 1;
+ } else if (audit_in_failure) {
+ /*
+ * Note: if we want to handle recovery, this is the
+ * spot to do it: unset audit_in_failure, and issue a
+ * wakeup on the cv.
+ */
+ }
+ }
+
+ error = vn_rdwr(UIO_WRITE, vp, data, len, (off_t)0, UIO_SYSSPACE,
+ IO_APPEND|IO_UNIT, cred, NULL, NULL, curthread);
+ if (error == ENOSPC)
+ goto fail_enospc;
+ else if (error)
+ goto fail;
+
+ /*
+ * Catch completion of a queue drain here; if we're draining and the
+ * queue is now empty, fail stop. That audit_fail_stop is implicitly
+ * true, since audit_in_failure can only be set of audit_fail_stop is
+ * set.
+ *
+ * Note: if we handle recovery from audit_in_failure, then we need to
+ * make panic here conditional.
+ */
+ if (audit_in_failure) {
+ if (audit_q_len == 0 && audit_pre_q_len == 0) {
+ VOP_LOCK(vp, LK_EXCLUSIVE | LK_RETRY);
+ (void)VOP_FSYNC(vp, MNT_WAIT, curthread);
+ VOP_UNLOCK(vp, 0);
+ panic("Audit store overflow; record queue drained.");
+ }
+ }
+
+ VFS_UNLOCK_GIANT(vfslocked);
+ return;
+
+fail_enospc:
+ /*
+ * ENOSPC is considered a special case with respect to failures, as
+ * this can reflect either our preemptive detection of insufficient
+ * space, or ENOSPC returned by the vnode write call.
+ */
+ if (audit_fail_stop) {
+ VOP_LOCK(vp, LK_EXCLUSIVE | LK_RETRY);
+ (void)VOP_FSYNC(vp, MNT_WAIT, curthread);
+ VOP_UNLOCK(vp, 0);
+ panic("Audit log space exhausted and fail-stop set.");
+ }
+ (void)audit_send_trigger(AUDIT_TRIGGER_NO_SPACE);
+ audit_suspended = 1;
+
+ /* FALLTHROUGH */
+fail:
+ /*
+ * We have failed to write to the file, so the current record is
+ * lost, which may require an immediate system halt.
+ */
+ if (audit_panic_on_write_fail) {
+ VOP_LOCK(vp, LK_EXCLUSIVE | LK_RETRY);
+ (void)VOP_FSYNC(vp, MNT_WAIT, curthread);
+ VOP_UNLOCK(vp, 0);
+ panic("audit_worker: write error %d\n", error);
+ } else if (ppsratecheck(&last_fail, &cur_fail, 1))
+ printf("audit_worker: write error %d\n", error);
+ VFS_UNLOCK_GIANT(vfslocked);
+}
+
+/*
+ * Given a kernel audit record, process as required. Kernel audit records
+ * are converted to one, or possibly two, BSM records, depending on whether
+ * there is a user audit record present also. Kernel records need be
+ * converted to BSM before they can be written out. Both types will be
+ * written to disk, and audit pipes.
+ */
+static void
+audit_worker_process_record(struct kaudit_record *ar)
+{
+ struct au_record *bsm;
+ au_class_t class;
+ au_event_t event;
+ au_id_t auid;
+ int error, sorf;
+ int locked;
+
+ /*
+ * We hold the audit worker lock over both writes, if there are two,
+ * so that the two records won't be split across a rotation and end
+ * up in two different trail files.
+ */
+ if (((ar->k_ar_commit & AR_COMMIT_USER) &&
+ (ar->k_ar_commit & AR_PRESELECT_USER_TRAIL)) ||
+ (ar->k_ar_commit & AR_PRESELECT_TRAIL)) {
+ AUDIT_WORKER_LOCK();
+ locked = 1;
+ } else
+ locked = 0;
+
+ /*
+ * First, handle the user record, if any: commit to the system trail
+ * and audit pipes as selected.
+ */
+ if ((ar->k_ar_commit & AR_COMMIT_USER) &&
+ (ar->k_ar_commit & AR_PRESELECT_USER_TRAIL)) {
+ AUDIT_WORKER_LOCK_ASSERT();
+ audit_record_write(audit_vp, audit_cred, ar->k_udata,
+ ar->k_ulen);
+ }
+
+ if ((ar->k_ar_commit & AR_COMMIT_USER) &&
+ (ar->k_ar_commit & AR_PRESELECT_USER_PIPE))
+ audit_pipe_submit_user(ar->k_udata, ar->k_ulen);
+
+ if (!(ar->k_ar_commit & AR_COMMIT_KERNEL) ||
+ ((ar->k_ar_commit & AR_PRESELECT_PIPE) == 0 &&
+ (ar->k_ar_commit & AR_PRESELECT_TRAIL) == 0))
+ goto out;
+
+ auid = ar->k_ar.ar_subj_auid;
+ event = ar->k_ar.ar_event;
+ class = au_event_class(event);
+ if (ar->k_ar.ar_errno == 0)
+ sorf = AU_PRS_SUCCESS;
+ else
+ sorf = AU_PRS_FAILURE;
+
+ error = kaudit_to_bsm(ar, &bsm);
+ switch (error) {
+ case BSM_NOAUDIT:
+ goto out;
+
+ case BSM_FAILURE:
+ printf("audit_worker_process_record: BSM_FAILURE\n");
+ goto out;
+
+ case BSM_SUCCESS:
+ break;
+
+ default:
+ panic("kaudit_to_bsm returned %d", error);
+ }
+
+ if (ar->k_ar_commit & AR_PRESELECT_TRAIL) {
+ AUDIT_WORKER_LOCK_ASSERT();
+ audit_record_write(audit_vp, audit_cred, bsm->data, bsm->len);
+ }
+
+ if (ar->k_ar_commit & AR_PRESELECT_PIPE)
+ audit_pipe_submit(auid, event, class, sorf,
+ ar->k_ar_commit & AR_PRESELECT_TRAIL, bsm->data,
+ bsm->len);
+
+ kau_free(bsm);
+out:
+ if (locked)
+ AUDIT_WORKER_UNLOCK();
+}
+
+/*
+ * The audit_worker thread is responsible for watching the event queue,
+ * dequeueing records, converting them to BSM format, and committing them to
+ * disk. In order to minimize lock thrashing, records are dequeued in sets
+ * to a thread-local work queue.
+ *
+ * Note: this means that the effect bound on the size of the pending record
+ * queue is 2x the length of the global queue.
+ */
+static void
+audit_worker(void *arg)
+{
+ struct kaudit_queue ar_worklist;
+ struct kaudit_record *ar;
+ int lowater_signal;
+
+ TAILQ_INIT(&ar_worklist);
+ mtx_lock(&audit_mtx);
+ while (1) {
+ mtx_assert(&audit_mtx, MA_OWNED);
+
+ /*
+ * Wait for a record.
+ */
+ while (TAILQ_EMPTY(&audit_q))
+ cv_wait(&audit_worker_cv, &audit_mtx);
+
+ /*
+ * If there are records in the global audit record queue,
+ * transfer them to a thread-local queue and process them
+ * one by one. If we cross the low watermark threshold,
+ * signal any waiting processes that they may wake up and
+ * continue generating records.
+ */
+ lowater_signal = 0;
+ while ((ar = TAILQ_FIRST(&audit_q))) {
+ TAILQ_REMOVE(&audit_q, ar, k_q);
+ audit_q_len--;
+ if (audit_q_len == audit_qctrl.aq_lowater)
+ lowater_signal++;
+ TAILQ_INSERT_TAIL(&ar_worklist, ar, k_q);
+ }
+ if (lowater_signal)
+ cv_broadcast(&audit_watermark_cv);
+
+ mtx_unlock(&audit_mtx);
+ while ((ar = TAILQ_FIRST(&ar_worklist))) {
+ TAILQ_REMOVE(&ar_worklist, ar, k_q);
+ audit_worker_process_record(ar);
+ audit_free(ar);
+ }
+ mtx_lock(&audit_mtx);
+ }
+}
+
+/*
+ * audit_rotate_vnode() is called by a user or kernel thread to configure or
+ * de-configure auditing on a vnode. The arguments are the replacement
+ * credential (referenced) and vnode (referenced and opened) to substitute
+ * for the current credential and vnode, if any. If either is set to NULL,
+ * both should be NULL, and this is used to indicate that audit is being
+ * disabled. Any previous cred/vnode will be closed and freed. We re-enable
+ * generating rotation requests to auditd.
+ */
+void
+audit_rotate_vnode(struct ucred *cred, struct vnode *vp)
+{
+ struct ucred *old_audit_cred;
+ struct vnode *old_audit_vp;
+ int vfslocked;
+
+ KASSERT((cred != NULL && vp != NULL) || (cred == NULL && vp == NULL),
+ ("audit_rotate_vnode: cred %p vp %p", cred, vp));
+
+ /*
+ * Rotate the vnode/cred, and clear the rotate flag so that we will
+ * send a rotate trigger if the new file fills.
+ */
+ AUDIT_WORKER_LOCK();
+ old_audit_cred = audit_cred;
+ old_audit_vp = audit_vp;
+ audit_cred = cred;
+ audit_vp = vp;
+ audit_file_rotate_wait = 0;
+ audit_enabled = (audit_vp != NULL);
+ AUDIT_WORKER_UNLOCK();
+
+ /*
+ * If there was an old vnode/credential, close and free.
+ */
+ if (old_audit_vp != NULL) {
+ vfslocked = VFS_LOCK_GIANT(old_audit_vp->v_mount);
+ vn_close(old_audit_vp, AUDIT_CLOSE_FLAGS, old_audit_cred,
+ curthread);
+ VFS_UNLOCK_GIANT(vfslocked);
+ crfree(old_audit_cred);
+ }
+}
+
+void
+audit_worker_init(void)
+{
+ int error;
+
+ AUDIT_WORKER_LOCK_INIT();
+ error = kproc_create(audit_worker, NULL, &audit_thread, RFHIGHPID,
+ 0, "audit");
+ if (error)
+ panic("audit_worker_init: kproc_create returned %d", error);
+}
diff --git a/sys/security/mac/mac_atalk.c b/sys/security/mac/mac_atalk.c
new file mode 100644
index 0000000..0992ee5
--- /dev/null
+++ b/sys/security/mac/mac_atalk.c
@@ -0,0 +1,66 @@
+/*-
+ * Copyright (c) 2007 Robert N. M. Watson
+ * All rights reserved.
+ *
+ * This software was developed by Robert Watson for the TrustedBSD Project.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "opt_mac.h"
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/mutex.h>
+#include <sys/sbuf.h>
+#include <sys/systm.h>
+#include <sys/mount.h>
+#include <sys/file.h>
+#include <sys/namei.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/sysctl.h>
+
+#include <net/if.h>
+#include <net/if_var.h>
+
+#include <security/mac/mac_framework.h>
+#include <security/mac/mac_internal.h>
+#include <security/mac/mac_policy.h>
+
+void
+mac_netatalk_aarp_send(struct ifnet *ifp, struct mbuf *m)
+{
+ struct label *mlabel;
+
+ mlabel = mac_mbuf_to_label(m);
+
+ MAC_IFNET_LOCK(ifp);
+ MAC_PERFORM(netatalk_aarp_send, ifp, ifp->if_label, m, mlabel);
+ MAC_IFNET_UNLOCK(ifp);
+}
diff --git a/sys/security/mac/mac_audit.c b/sys/security/mac/mac_audit.c
new file mode 100644
index 0000000..d8cd8e6
--- /dev/null
+++ b/sys/security/mac/mac_audit.c
@@ -0,0 +1,115 @@
+/*-
+ * Copyright (c) 1999-2002 Robert N. M. Watson
+ * Copyright (c) 2001 Ilmar S. Habibulin
+ * Copyright (c) 2001-2004 Networks Associates Technology, Inc.
+ * Copyright (c) 2006 SPARTA, Inc.
+ *
+ * This software was developed by Robert Watson and Ilmar Habibulin for the
+ * TrustedBSD Project.
+ *
+ * This software was developed for the FreeBSD Project in part by Network
+ * Associates Laboratories, the Security Research Division of Network
+ * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"),
+ * as part of the DARPA CHATS research program.
+ *
+ * This software was enhanced by SPARTA ISSO under SPAWAR contract
+ * N66001-04-C-6019 ("SEFOS").
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/param.h>
+#include <sys/module.h>
+#include <sys/vnode.h>
+
+#include <security/audit/audit.h>
+
+#include <security/mac/mac_framework.h>
+#include <security/mac/mac_internal.h>
+#include <security/mac/mac_policy.h>
+
+int
+mac_proc_check_setaudit(struct ucred *cred, struct auditinfo *ai)
+{
+ int error;
+
+ MAC_CHECK(proc_check_setaudit, cred, ai);
+
+ return (error);
+}
+
+int
+mac_proc_check_setaudit_addr(struct ucred *cred, struct auditinfo_addr *aia)
+{
+ int error;
+
+ MAC_CHECK(proc_check_setaudit_addr, cred, aia);
+
+ return (error);
+}
+
+int
+mac_proc_check_setauid(struct ucred *cred, uid_t auid)
+{
+ int error;
+
+ MAC_CHECK(proc_check_setauid, cred, auid);
+
+ return (error);
+}
+
+int
+mac_system_check_audit(struct ucred *cred, void *record, int length)
+{
+ int error;
+
+ MAC_CHECK(system_check_audit, cred, record, length);
+
+ return (error);
+}
+
+int
+mac_system_check_auditctl(struct ucred *cred, struct vnode *vp)
+{
+ int error;
+ struct label *vl;
+
+ ASSERT_VOP_LOCKED(vp, "mac_system_check_auditctl");
+
+ vl = (vp != NULL) ? vp->v_label : NULL;
+
+ MAC_CHECK(system_check_auditctl, cred, vp, vl);
+
+ return (error);
+}
+
+int
+mac_system_check_auditon(struct ucred *cred, int cmd)
+{
+ int error;
+
+ MAC_CHECK(system_check_auditon, cred, cmd);
+
+ return (error);
+}
diff --git a/sys/security/mac/mac_cred.c b/sys/security/mac/mac_cred.c
new file mode 100644
index 0000000..4d46f9a
--- /dev/null
+++ b/sys/security/mac/mac_cred.c
@@ -0,0 +1,213 @@
+/*-
+ * Copyright (c) 1999-2002, 2008 Robert N. M. Watson
+ * Copyright (c) 2001 Ilmar S. Habibulin
+ * Copyright (c) 2001-2003 Networks Associates Technology, Inc.
+ * Copyright (c) 2005 Samy Al Bahra
+ * Copyright (c) 2006 SPARTA, Inc.
+ * Copyright (c) 2008 Apple Inc.
+ * All rights reserved.
+ *
+ * This software was developed by Robert Watson and Ilmar Habibulin for the
+ * TrustedBSD Project.
+ *
+ * This software was developed for the FreeBSD Project in part by Network
+ * Associates Laboratories, the Security Research Division of Network
+ * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"),
+ * as part of the DARPA CHATS research program.
+ *
+ * This software was enhanced by SPARTA ISSO under SPAWAR contract
+ * N66001-04-C-6019 ("SEFOS").
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "opt_mac.h"
+
+#include <sys/param.h>
+#include <sys/condvar.h>
+#include <sys/imgact.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/mutex.h>
+#include <sys/mac.h>
+#include <sys/proc.h>
+#include <sys/sbuf.h>
+#include <sys/systm.h>
+#include <sys/vnode.h>
+#include <sys/mount.h>
+#include <sys/file.h>
+#include <sys/namei.h>
+#include <sys/sysctl.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+#include <vm/vm_map.h>
+#include <vm/vm_object.h>
+
+#include <security/mac/mac_framework.h>
+#include <security/mac/mac_internal.h>
+#include <security/mac/mac_policy.h>
+
+struct label *
+mac_cred_label_alloc(void)
+{
+ struct label *label;
+
+ label = mac_labelzone_alloc(M_WAITOK);
+ MAC_PERFORM(cred_init_label, label);
+ return (label);
+}
+
+void
+mac_cred_init(struct ucred *cred)
+{
+
+ if (mac_labeled & MPC_OBJECT_CRED)
+ cred->cr_label = mac_cred_label_alloc();
+ else
+ cred->cr_label = NULL;
+}
+
+void
+mac_cred_label_free(struct label *label)
+{
+
+ MAC_PERFORM(cred_destroy_label, label);
+ mac_labelzone_free(label);
+}
+
+void
+mac_cred_destroy(struct ucred *cred)
+{
+
+ if (cred->cr_label != NULL) {
+ mac_cred_label_free(cred->cr_label);
+ cred->cr_label = NULL;
+ }
+}
+
+/*
+ * When a thread becomes an NFS server daemon, its credential may need to be
+ * updated to reflect this so that policies can recognize when file system
+ * operations originate from the network.
+ *
+ * At some point, it would be desirable if the credential used for each NFS
+ * RPC could be set based on the RPC context (i.e., source system, etc) to
+ * provide more fine-grained access control.
+ */
+void
+mac_cred_associate_nfsd(struct ucred *cred)
+{
+
+ MAC_PERFORM(cred_associate_nfsd, cred);
+}
+
+/*
+ * Initialize MAC label for the first kernel process, from which other kernel
+ * processes and threads are spawned.
+ */
+void
+mac_cred_create_swapper(struct ucred *cred)
+{
+
+ MAC_PERFORM(cred_create_swapper, cred);
+}
+
+/*
+ * Initialize MAC label for the first userland process, from which other
+ * userland processes and threads are spawned.
+ */
+void
+mac_cred_create_init(struct ucred *cred)
+{
+
+ MAC_PERFORM(cred_create_init, cred);
+}
+
+int
+mac_cred_externalize_label(struct label *label, char *elements,
+ char *outbuf, size_t outbuflen)
+{
+ int error;
+
+ MAC_EXTERNALIZE(cred, label, elements, outbuf, outbuflen);
+
+ return (error);
+}
+
+int
+mac_cred_internalize_label(struct label *label, char *string)
+{
+ int error;
+
+ MAC_INTERNALIZE(cred, label, string);
+
+ return (error);
+}
+
+/*
+ * When a new process is created, its label must be initialized. Generally,
+ * this involves inheritence from the parent process, modulo possible deltas.
+ * This function allows that processing to take place.
+ */
+void
+mac_cred_copy(struct ucred *src, struct ucred *dest)
+{
+
+ MAC_PERFORM(cred_copy_label, src->cr_label, dest->cr_label);
+}
+
+/*
+ * When the subject's label changes, it may require revocation of privilege
+ * to mapped objects. This can't be done on-the-fly later with a unified
+ * buffer cache.
+ */
+void
+mac_cred_relabel(struct ucred *cred, struct label *newlabel)
+{
+
+ MAC_PERFORM(cred_relabel, cred, newlabel);
+}
+
+int
+mac_cred_check_relabel(struct ucred *cred, struct label *newlabel)
+{
+ int error;
+
+ MAC_CHECK(cred_check_relabel, cred, newlabel);
+
+ return (error);
+}
+
+int
+mac_cred_check_visible(struct ucred *cr1, struct ucred *cr2)
+{
+ int error;
+
+ MAC_CHECK(cred_check_visible, cr1, cr2);
+
+ return (error);
+}
diff --git a/sys/security/mac/mac_framework.c b/sys/security/mac/mac_framework.c
new file mode 100644
index 0000000..0a7b085
--- /dev/null
+++ b/sys/security/mac/mac_framework.c
@@ -0,0 +1,571 @@
+/*-
+ * Copyright (c) 1999-2002, 2006 Robert N. M. Watson
+ * Copyright (c) 2001 Ilmar S. Habibulin
+ * Copyright (c) 2001-2005 Networks Associates Technology, Inc.
+ * Copyright (c) 2005-2006 SPARTA, Inc.
+ * Copyright (c) 2008 Apple Inc.
+ * All rights reserved.
+ *
+ * This software was developed by Robert Watson and Ilmar Habibulin for the
+ * TrustedBSD Project.
+ *
+ * This software was developed for the FreeBSD Project in part by Network
+ * Associates Laboratories, the Security Research Division of Network
+ * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"),
+ * as part of the DARPA CHATS research program.
+ *
+ * This software was enhanced by SPARTA ISSO under SPAWAR contract
+ * N66001-04-C-6019 ("SEFOS").
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*-
+ * Framework for extensible kernel access control. This file contains core
+ * kernel infrastructure for the TrustedBSD MAC Framework, including policy
+ * registration, versioning, locking, error composition operator, and system
+ * calls.
+ *
+ * The MAC Framework implements three programming interfaces:
+ *
+ * - The kernel MAC interface, defined in mac_framework.h, and invoked
+ * throughout the kernel to request security decisions, notify of security
+ * related events, etc.
+ *
+ * - The MAC policy module interface, defined in mac_policy.h, which is
+ * implemented by MAC policy modules and invoked by the MAC Framework to
+ * forward kernel security requests and notifications to policy modules.
+ *
+ * - The user MAC API, defined in mac.h, which allows user programs to query
+ * and set label state on objects.
+ *
+ * The majority of the MAC Framework implementation may be found in
+ * src/sys/security/mac. Sample policy modules may be found in
+ * src/sys/security/mac_*.
+ */
+
+#include "opt_mac.h"
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/condvar.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/mac.h>
+#include <sys/module.h>
+#include <sys/systm.h>
+#include <sys/sysctl.h>
+
+#include <security/mac/mac_framework.h>
+#include <security/mac/mac_internal.h>
+#include <security/mac/mac_policy.h>
+
+/*
+ * Root sysctl node for all MAC and MAC policy controls.
+ */
+SYSCTL_NODE(_security, OID_AUTO, mac, CTLFLAG_RW, 0,
+ "TrustedBSD MAC policy controls");
+
+/*
+ * Declare that the kernel provides MAC support, version 3 (FreeBSD 7.x).
+ * This permits modules to refuse to be loaded if the necessary support isn't
+ * present, even if it's pre-boot.
+ */
+MODULE_VERSION(kernel_mac_support, MAC_VERSION);
+
+static unsigned int mac_version = MAC_VERSION;
+SYSCTL_UINT(_security_mac, OID_AUTO, version, CTLFLAG_RD, &mac_version, 0,
+ "");
+
+/*
+ * Labels consist of a indexed set of "slots", which are allocated policies
+ * as required. The MAC Framework maintains a bitmask of slots allocated so
+ * far to prevent reuse. Slots cannot be reused, as the MAC Framework
+ * guarantees that newly allocated slots in labels will be NULL unless
+ * otherwise initialized, and because we do not have a mechanism to garbage
+ * collect slots on policy unload. As labeled policies tend to be statically
+ * loaded during boot, and not frequently unloaded and reloaded, this is not
+ * generally an issue.
+ */
+#if MAC_MAX_SLOTS > 32
+#error "MAC_MAX_SLOTS too large"
+#endif
+
+static unsigned int mac_max_slots = MAC_MAX_SLOTS;
+static unsigned int mac_slot_offsets_free = (1 << MAC_MAX_SLOTS) - 1;
+SYSCTL_UINT(_security_mac, OID_AUTO, max_slots, CTLFLAG_RD, &mac_max_slots,
+ 0, "");
+
+/*
+ * Has the kernel started generating labeled objects yet? All read/write
+ * access to this variable is serialized during the boot process. Following
+ * the end of serialization, we don't update this flag; no locking.
+ */
+static int mac_late = 0;
+
+/*
+ * Each policy declares a mask of object types requiring labels to be
+ * allocated for them. For convenience, we combine and cache the bitwise or
+ * of the per-policy object flags to track whether we will allocate a label
+ * for an object type at run-time.
+ */
+uint64_t mac_labeled;
+SYSCTL_QUAD(_security_mac, OID_AUTO, labeled, CTLFLAG_RD, &mac_labeled, 0,
+ "Mask of object types being labeled");
+
+MALLOC_DEFINE(M_MACTEMP, "mactemp", "MAC temporary label storage");
+
+/*
+ * mac_static_policy_list holds a list of policy modules that are not loaded
+ * while the system is "live", and cannot be unloaded. These policies can be
+ * invoked without holding the busy count.
+ *
+ * mac_policy_list stores the list of dynamic policies. A busy count is
+ * maintained for the list, stored in mac_policy_busy. The busy count is
+ * protected by mac_policy_mtx; the list may be modified only while the busy
+ * count is 0, requiring that the lock be held to prevent new references to
+ * the list from being acquired. For almost all operations, incrementing the
+ * busy count is sufficient to guarantee consistency, as the list cannot be
+ * modified while the busy count is elevated. For a few special operations
+ * involving a change to the list of active policies, the mtx itself must be
+ * held. A condition variable, mac_policy_cv, is used to signal potential
+ * exclusive consumers that they should try to acquire the lock if a first
+ * attempt at exclusive access fails.
+ *
+ * This design intentionally avoids fairness, and may starve attempts to
+ * acquire an exclusive lock on a busy system. This is required because we
+ * do not ever want acquiring a read reference to perform an unbounded length
+ * sleep. Read references are acquired in ithreads, network isrs, etc, and
+ * any unbounded blocking could lead quickly to deadlock.
+ *
+ * Another reason for never blocking on read references is that the MAC
+ * Framework may recurse: if a policy calls a VOP, for example, this might
+ * lead to vnode life cycle operations (such as init/destroy).
+ *
+ * If the kernel option MAC_STATIC has been compiled in, all locking becomes
+ * a no-op, and the global list of policies is not allowed to change after
+ * early boot.
+ *
+ * XXXRW: Currently, we signal mac_policy_cv every time the framework becomes
+ * unbusy and there is a thread waiting to enter it exclusively. Since it
+ * may take some time before the thread runs, we may issue a lot of signals.
+ * We should instead keep track of the fact that we've signalled, taking into
+ * account that the framework may be busy again by the time the thread runs,
+ * requiring us to re-signal.
+ */
+#ifndef MAC_STATIC
+static struct mtx mac_policy_mtx;
+static struct cv mac_policy_cv;
+static int mac_policy_count;
+static int mac_policy_wait;
+#endif
+struct mac_policy_list_head mac_policy_list;
+struct mac_policy_list_head mac_static_policy_list;
+
+/*
+ * We manually invoke WITNESS_WARN() to allow Witness to generate warnings
+ * even if we don't end up ever triggering the wait at run-time. The
+ * consumer of the exclusive interface must not hold any locks (other than
+ * potentially Giant) since we may sleep for long (potentially indefinite)
+ * periods of time waiting for the framework to become quiescent so that a
+ * policy list change may be made.
+ */
+void
+mac_policy_grab_exclusive(void)
+{
+
+#ifndef MAC_STATIC
+ if (!mac_late)
+ return;
+
+ WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL,
+ "mac_policy_grab_exclusive() at %s:%d", __FILE__, __LINE__);
+ mtx_lock(&mac_policy_mtx);
+ while (mac_policy_count != 0) {
+ mac_policy_wait++;
+ cv_wait(&mac_policy_cv, &mac_policy_mtx);
+ mac_policy_wait--;
+ }
+#endif
+}
+
+void
+mac_policy_assert_exclusive(void)
+{
+
+#ifndef MAC_STATIC
+ if (!mac_late)
+ return;
+
+ mtx_assert(&mac_policy_mtx, MA_OWNED);
+ KASSERT(mac_policy_count == 0,
+ ("mac_policy_assert_exclusive(): not exclusive"));
+#endif
+}
+
+void
+mac_policy_release_exclusive(void)
+{
+#ifndef MAC_STATIC
+ int dowakeup;
+
+ if (!mac_late)
+ return;
+
+ KASSERT(mac_policy_count == 0,
+ ("mac_policy_release_exclusive(): not exclusive"));
+ dowakeup = (mac_policy_wait != 0);
+ mtx_unlock(&mac_policy_mtx);
+ if (dowakeup)
+ cv_signal(&mac_policy_cv);
+#endif
+}
+
+void
+mac_policy_list_busy(void)
+{
+
+#ifndef MAC_STATIC
+ if (!mac_late)
+ return;
+
+ mtx_lock(&mac_policy_mtx);
+ mac_policy_count++;
+ mtx_unlock(&mac_policy_mtx);
+#endif
+}
+
+int
+mac_policy_list_conditional_busy(void)
+{
+#ifndef MAC_STATIC
+ int ret;
+
+ if (!mac_late)
+ return (1);
+
+ mtx_lock(&mac_policy_mtx);
+ if (!LIST_EMPTY(&mac_policy_list)) {
+ mac_policy_count++;
+ ret = 1;
+ } else
+ ret = 0;
+ mtx_unlock(&mac_policy_mtx);
+ return (ret);
+#else
+ return (1);
+#endif
+}
+
+void
+mac_policy_list_unbusy(void)
+{
+#ifndef MAC_STATIC
+ int dowakeup;
+
+ if (!mac_late)
+ return;
+
+ mtx_lock(&mac_policy_mtx);
+ mac_policy_count--;
+ KASSERT(mac_policy_count >= 0, ("MAC_POLICY_LIST_LOCK"));
+ dowakeup = (mac_policy_count == 0 && mac_policy_wait != 0);
+ mtx_unlock(&mac_policy_mtx);
+
+ if (dowakeup)
+ cv_signal(&mac_policy_cv);
+#endif
+}
+
+/*
+ * Initialize the MAC subsystem, including appropriate SMP locks.
+ */
+static void
+mac_init(void)
+{
+
+ LIST_INIT(&mac_static_policy_list);
+ LIST_INIT(&mac_policy_list);
+ mac_labelzone_init();
+
+#ifndef MAC_STATIC
+ mtx_init(&mac_policy_mtx, "mac_policy_mtx", NULL, MTX_DEF);
+ cv_init(&mac_policy_cv, "mac_policy_cv");
+#endif
+}
+
+/*
+ * For the purposes of modules that want to know if they were loaded "early",
+ * set the mac_late flag once we've processed modules either linked into the
+ * kernel, or loaded before the kernel startup.
+ */
+static void
+mac_late_init(void)
+{
+
+ mac_late = 1;
+}
+
+/*
+ * After the policy list has changed, walk the list to update any global
+ * flags. Currently, we support only one flag, and it's conditionally
+ * defined; as a result, the entire function is conditional. Eventually, the
+ * #else case might also iterate across the policies.
+ */
+static void
+mac_policy_updateflags(void)
+{
+ struct mac_policy_conf *mpc;
+
+ mac_policy_assert_exclusive();
+
+ mac_labeled = 0;
+ LIST_FOREACH(mpc, &mac_static_policy_list, mpc_list)
+ mac_labeled |= mpc->mpc_labeled;
+ LIST_FOREACH(mpc, &mac_policy_list, mpc_list)
+ mac_labeled |= mpc->mpc_labeled;
+}
+
+static int
+mac_policy_register(struct mac_policy_conf *mpc)
+{
+ struct mac_policy_conf *tmpc;
+ int error, slot, static_entry;
+
+ error = 0;
+
+ /*
+ * We don't technically need exclusive access while !mac_late, but
+ * hold it for assertion consistency.
+ */
+ mac_policy_grab_exclusive();
+
+ /*
+ * If the module can potentially be unloaded, or we're loading late,
+ * we have to stick it in the non-static list and pay an extra
+ * performance overhead. Otherwise, we can pay a light locking cost
+ * and stick it in the static list.
+ */
+ static_entry = (!mac_late &&
+ !(mpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_UNLOADOK));
+
+ if (static_entry) {
+ LIST_FOREACH(tmpc, &mac_static_policy_list, mpc_list) {
+ if (strcmp(tmpc->mpc_name, mpc->mpc_name) == 0) {
+ error = EEXIST;
+ goto out;
+ }
+ }
+ } else {
+ LIST_FOREACH(tmpc, &mac_policy_list, mpc_list) {
+ if (strcmp(tmpc->mpc_name, mpc->mpc_name) == 0) {
+ error = EEXIST;
+ goto out;
+ }
+ }
+ }
+ if (mpc->mpc_field_off != NULL) {
+ slot = ffs(mac_slot_offsets_free);
+ if (slot == 0) {
+ error = ENOMEM;
+ goto out;
+ }
+ slot--;
+ mac_slot_offsets_free &= ~(1 << slot);
+ *mpc->mpc_field_off = slot;
+ }
+ mpc->mpc_runtime_flags |= MPC_RUNTIME_FLAG_REGISTERED;
+
+ /*
+ * If we're loading a MAC module after the framework has initialized,
+ * it has to go into the dynamic list. If we're loading it before
+ * we've finished initializing, it can go into the static list with
+ * weaker locker requirements.
+ */
+ if (static_entry)
+ LIST_INSERT_HEAD(&mac_static_policy_list, mpc, mpc_list);
+ else
+ LIST_INSERT_HEAD(&mac_policy_list, mpc, mpc_list);
+
+ /*
+ * Per-policy initialization. Currently, this takes place under the
+ * exclusive lock, so policies must not sleep in their init method.
+ * In the future, we may want to separate "init" from "start", with
+ * "init" occuring without the lock held. Likewise, on tear-down,
+ * breaking out "stop" from "destroy".
+ */
+ if (mpc->mpc_ops->mpo_init != NULL)
+ (*(mpc->mpc_ops->mpo_init))(mpc);
+ mac_policy_updateflags();
+
+ printf("Security policy loaded: %s (%s)\n", mpc->mpc_fullname,
+ mpc->mpc_name);
+
+out:
+ mac_policy_release_exclusive();
+ return (error);
+}
+
+static int
+mac_policy_unregister(struct mac_policy_conf *mpc)
+{
+
+ /*
+ * If we fail the load, we may get a request to unload. Check to see
+ * if we did the run-time registration, and if not, silently succeed.
+ */
+ mac_policy_grab_exclusive();
+ if ((mpc->mpc_runtime_flags & MPC_RUNTIME_FLAG_REGISTERED) == 0) {
+ mac_policy_release_exclusive();
+ return (0);
+ }
+#if 0
+ /*
+ * Don't allow unloading modules with private data.
+ */
+ if (mpc->mpc_field_off != NULL) {
+ MAC_POLICY_LIST_UNLOCK();
+ return (EBUSY);
+ }
+#endif
+ /*
+ * Only allow the unload to proceed if the module is unloadable by
+ * its own definition.
+ */
+ if ((mpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_UNLOADOK) == 0) {
+ mac_policy_release_exclusive();
+ return (EBUSY);
+ }
+ if (mpc->mpc_ops->mpo_destroy != NULL)
+ (*(mpc->mpc_ops->mpo_destroy))(mpc);
+
+ LIST_REMOVE(mpc, mpc_list);
+ mpc->mpc_runtime_flags &= ~MPC_RUNTIME_FLAG_REGISTERED;
+ mac_policy_updateflags();
+
+ mac_policy_release_exclusive();
+
+ printf("Security policy unload: %s (%s)\n", mpc->mpc_fullname,
+ mpc->mpc_name);
+
+ return (0);
+}
+
+/*
+ * Allow MAC policy modules to register during boot, etc.
+ */
+int
+mac_policy_modevent(module_t mod, int type, void *data)
+{
+ struct mac_policy_conf *mpc;
+ int error;
+
+ error = 0;
+ mpc = (struct mac_policy_conf *) data;
+
+#ifdef MAC_STATIC
+ if (mac_late) {
+ printf("mac_policy_modevent: MAC_STATIC and late\n");
+ return (EBUSY);
+ }
+#endif
+
+ switch (type) {
+ case MOD_LOAD:
+ if (mpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_NOTLATE &&
+ mac_late) {
+ printf("mac_policy_modevent: can't load %s policy "
+ "after booting\n", mpc->mpc_name);
+ error = EBUSY;
+ break;
+ }
+ error = mac_policy_register(mpc);
+ break;
+ case MOD_UNLOAD:
+ /* Don't unregister the module if it was never registered. */
+ if ((mpc->mpc_runtime_flags & MPC_RUNTIME_FLAG_REGISTERED)
+ != 0)
+ error = mac_policy_unregister(mpc);
+ else
+ error = 0;
+ break;
+ default:
+ error = EOPNOTSUPP;
+ break;
+ }
+
+ return (error);
+}
+
+/*
+ * Define an error value precedence, and given two arguments, selects the
+ * value with the higher precedence.
+ */
+int
+mac_error_select(int error1, int error2)
+{
+
+ /* Certain decision-making errors take top priority. */
+ if (error1 == EDEADLK || error2 == EDEADLK)
+ return (EDEADLK);
+
+ /* Invalid arguments should be reported where possible. */
+ if (error1 == EINVAL || error2 == EINVAL)
+ return (EINVAL);
+
+ /* Precedence goes to "visibility", with both process and file. */
+ if (error1 == ESRCH || error2 == ESRCH)
+ return (ESRCH);
+
+ if (error1 == ENOENT || error2 == ENOENT)
+ return (ENOENT);
+
+ /* Precedence goes to DAC/MAC protections. */
+ if (error1 == EACCES || error2 == EACCES)
+ return (EACCES);
+
+ /* Precedence goes to privilege. */
+ if (error1 == EPERM || error2 == EPERM)
+ return (EPERM);
+
+ /* Precedence goes to error over success; otherwise, arbitrary. */
+ if (error1 != 0)
+ return (error1);
+ return (error2);
+}
+
+int
+mac_check_structmac_consistent(struct mac *mac)
+{
+
+ if (mac->m_buflen < 0 ||
+ mac->m_buflen > MAC_MAX_LABEL_BUF_LEN)
+ return (EINVAL);
+
+ return (0);
+}
+
+SYSINIT(mac, SI_SUB_MAC, SI_ORDER_FIRST, mac_init, NULL);
+SYSINIT(mac_late, SI_SUB_MAC_LATE, SI_ORDER_FIRST, mac_late_init, NULL);
diff --git a/sys/security/mac/mac_framework.h b/sys/security/mac/mac_framework.h
new file mode 100644
index 0000000..4da4af9
--- /dev/null
+++ b/sys/security/mac/mac_framework.h
@@ -0,0 +1,445 @@
+/*-
+ * Copyright (c) 1999-2002, 2007-2008 Robert N. M. Watson
+ * Copyright (c) 2001-2005 Networks Associates Technology, Inc.
+ * Copyright (c) 2005-2006 SPARTA, Inc.
+ * All rights reserved.
+ *
+ * This software was developed by Robert Watson for the TrustedBSD Project.
+ *
+ * This software was developed for the FreeBSD Project in part by Network
+ * Associates Laboratories, the Security Research Division of Network
+ * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"),
+ * as part of the DARPA CHATS research program.
+ *
+ * This software was enhanced by SPARTA ISSO under SPAWAR contract
+ * N66001-04-C-6019 ("SEFOS").
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Kernel interface for Mandatory Access Control -- how kernel services
+ * interact with the TrustedBSD MAC Framework.
+ */
+
+#ifndef _SECURITY_MAC_MAC_FRAMEWORK_H_
+#define _SECURITY_MAC_MAC_FRAMEWORK_H_
+
+#ifndef _KERNEL
+#error "no user-serviceable parts inside"
+#endif
+
+struct auditinfo;
+struct auditinfo_addr;
+struct bpf_d;
+struct cdev;
+struct componentname;
+struct devfs_dirent;
+struct ifnet;
+struct ifreq;
+struct image_params;
+struct inpcb;
+struct ip6q;
+struct ipq;
+struct ksem;
+struct label;
+struct m_tag;
+struct mac;
+struct mbuf;
+struct mount;
+struct msg;
+struct msqid_kernel;
+struct proc;
+struct semid_kernel;
+struct shmfd;
+struct shmid_kernel;
+struct sockaddr;
+struct socket;
+struct sysctl_oid;
+struct sysctl_req;
+struct pipepair;
+struct thread;
+struct timespec;
+struct ucred;
+struct uio;
+struct vattr;
+struct vnode;
+struct vop_setlabel_args;
+
+#include <sys/acl.h> /* XXX acl_type_t */
+#include <sys/types.h> /* accmode_t */
+
+/*
+ * Entry points to the TrustedBSD MAC Framework from the remainder of the
+ * kernel: entry points are named based on a principle object type and an
+ * action relating to it. They are sorted alphabetically first by object
+ * type and then action. In some situations, the principle object type is
+ * obvious, and in other cases, less so as multiple objects may be inolved
+ * in the operation.
+ */
+int mac_bpfdesc_check_receive(struct bpf_d *d, struct ifnet *ifp);
+void mac_bpfdesc_create(struct ucred *cred, struct bpf_d *d);
+void mac_bpfdesc_create_mbuf(struct bpf_d *d, struct mbuf *m);
+void mac_bpfdesc_destroy(struct bpf_d *);
+void mac_bpfdesc_init(struct bpf_d *);
+
+void mac_cred_associate_nfsd(struct ucred *cred);
+int mac_cred_check_visible(struct ucred *cr1, struct ucred *cr2);
+void mac_cred_copy(struct ucred *cr1, struct ucred *cr2);
+void mac_cred_create_init(struct ucred *cred);
+void mac_cred_create_swapper(struct ucred *cred);
+void mac_cred_destroy(struct ucred *);
+void mac_cred_init(struct ucred *);
+
+void mac_devfs_create_device(struct ucred *cred, struct mount *mp,
+ struct cdev *dev, struct devfs_dirent *de);
+void mac_devfs_create_directory(struct mount *mp, char *dirname,
+ int dirnamelen, struct devfs_dirent *de);
+void mac_devfs_create_symlink(struct ucred *cred, struct mount *mp,
+ struct devfs_dirent *dd, struct devfs_dirent *de);
+void mac_devfs_destroy(struct devfs_dirent *);
+void mac_devfs_init(struct devfs_dirent *);
+void mac_devfs_update(struct mount *mp, struct devfs_dirent *de,
+ struct vnode *vp);
+void mac_devfs_vnode_associate(struct mount *mp, struct devfs_dirent *de,
+ struct vnode *vp);
+
+int mac_ifnet_check_transmit(struct ifnet *ifp, struct mbuf *m);
+void mac_ifnet_create(struct ifnet *ifp);
+void mac_ifnet_create_mbuf(struct ifnet *ifp, struct mbuf *m);
+void mac_ifnet_destroy(struct ifnet *);
+void mac_ifnet_init(struct ifnet *);
+int mac_ifnet_ioctl_get(struct ucred *cred, struct ifreq *ifr,
+ struct ifnet *ifp);
+int mac_ifnet_ioctl_set(struct ucred *cred, struct ifreq *ifr,
+ struct ifnet *ifp);
+
+int mac_inpcb_check_deliver(struct inpcb *inp, struct mbuf *m);
+int mac_inpcb_check_visible(struct ucred *cred, struct inpcb *inp);
+void mac_inpcb_create(struct socket *so, struct inpcb *inp);
+void mac_inpcb_create_mbuf(struct inpcb *inp, struct mbuf *m);
+void mac_inpcb_destroy(struct inpcb *);
+int mac_inpcb_init(struct inpcb *, int);
+void mac_inpcb_sosetlabel(struct socket *so, struct inpcb *inp);
+
+void mac_ip6q_create(struct mbuf *m, struct ip6q *q6);
+void mac_ip6q_destroy(struct ip6q *q6);
+int mac_ip6q_init(struct ip6q *q6, int);
+int mac_ip6q_match(struct mbuf *m, struct ip6q *q6);
+void mac_ip6q_reassemble(struct ip6q *q6, struct mbuf *m);
+void mac_ip6q_update(struct mbuf *m, struct ip6q *q6);
+
+void mac_ipq_create(struct mbuf *m, struct ipq *q);
+void mac_ipq_destroy(struct ipq *q);
+int mac_ipq_init(struct ipq *q, int);
+int mac_ipq_match(struct mbuf *m, struct ipq *q);
+void mac_ipq_reassemble(struct ipq *q, struct mbuf *m);
+void mac_ipq_update(struct mbuf *m, struct ipq *q);
+
+int mac_kenv_check_dump(struct ucred *cred);
+int mac_kenv_check_get(struct ucred *cred, char *name);
+int mac_kenv_check_set(struct ucred *cred, char *name, char *value);
+int mac_kenv_check_unset(struct ucred *cred, char *name);
+
+int mac_kld_check_load(struct ucred *cred, struct vnode *vp);
+int mac_kld_check_stat(struct ucred *cred);
+
+void mac_mbuf_copy(struct mbuf *, struct mbuf *);
+int mac_mbuf_init(struct mbuf *, int);
+
+void mac_mbuf_tag_copy(struct m_tag *, struct m_tag *);
+void mac_mbuf_tag_destroy(struct m_tag *);
+int mac_mbuf_tag_init(struct m_tag *, int);
+
+int mac_mount_check_stat(struct ucred *cred, struct mount *mp);
+void mac_mount_create(struct ucred *cred, struct mount *mp);
+void mac_mount_destroy(struct mount *);
+void mac_mount_init(struct mount *);
+
+void mac_netatalk_aarp_send(struct ifnet *ifp, struct mbuf *m);
+
+void mac_netinet_arp_send(struct ifnet *ifp, struct mbuf *m);
+void mac_netinet_firewall_reply(struct mbuf *mrecv, struct mbuf *msend);
+void mac_netinet_firewall_send(struct mbuf *m);
+void mac_netinet_fragment(struct mbuf *m, struct mbuf *frag);
+void mac_netinet_icmp_reply(struct mbuf *mrecv, struct mbuf *msend);
+void mac_netinet_icmp_replyinplace(struct mbuf *m);
+void mac_netinet_igmp_send(struct ifnet *ifp, struct mbuf *m);
+void mac_netinet_tcp_reply(struct mbuf *m);
+
+void mac_netinet6_nd6_send(struct ifnet *ifp, struct mbuf *m);
+
+int mac_pipe_check_ioctl(struct ucred *cred, struct pipepair *pp,
+ unsigned long cmd, void *data);
+int mac_pipe_check_poll(struct ucred *cred, struct pipepair *pp);
+int mac_pipe_check_read(struct ucred *cred, struct pipepair *pp);
+int mac_pipe_check_stat(struct ucred *cred, struct pipepair *pp);
+int mac_pipe_check_write(struct ucred *cred, struct pipepair *pp);
+void mac_pipe_create(struct ucred *cred, struct pipepair *pp);
+void mac_pipe_destroy(struct pipepair *);
+void mac_pipe_init(struct pipepair *);
+int mac_pipe_label_set(struct ucred *cred, struct pipepair *pp,
+ struct label *label);
+
+int mac_posixsem_check_getvalue(struct ucred *active_cred,
+ struct ucred *file_cred, struct ksem *ks);
+int mac_posixsem_check_open(struct ucred *cred, struct ksem *ks);
+int mac_posixsem_check_post(struct ucred *active_cred,
+ struct ucred *file_cred, struct ksem *ks);
+int mac_posixsem_check_stat(struct ucred *active_cred,
+ struct ucred *file_cred, struct ksem *ks);
+int mac_posixsem_check_unlink(struct ucred *cred, struct ksem *ks);
+int mac_posixsem_check_wait(struct ucred *active_cred,
+ struct ucred *file_cred, struct ksem *ks);
+void mac_posixsem_create(struct ucred *cred, struct ksem *ks);
+void mac_posixsem_destroy(struct ksem *);
+void mac_posixsem_init(struct ksem *);
+
+int mac_posixshm_check_mmap(struct ucred *cred, struct shmfd *shmfd,
+ int prot, int flags);
+int mac_posixshm_check_open(struct ucred *cred, struct shmfd *shmfd);
+int mac_posixshm_check_stat(struct ucred *active_cred,
+ struct ucred *file_cred, struct shmfd *shmfd);
+int mac_posixshm_check_truncate(struct ucred *active_cred,
+ struct ucred *file_cred, struct shmfd *shmfd);
+int mac_posixshm_check_unlink(struct ucred *cred, struct shmfd *shmfd);
+void mac_posixshm_create(struct ucred *cred, struct shmfd *shmfd);
+void mac_posixshm_destroy(struct shmfd *);
+void mac_posixshm_init(struct shmfd *);
+
+int mac_priv_check(struct ucred *cred, int priv);
+int mac_priv_grant(struct ucred *cred, int priv);
+
+int mac_proc_check_debug(struct ucred *cred, struct proc *p);
+int mac_proc_check_sched(struct ucred *cred, struct proc *p);
+int mac_proc_check_setaudit(struct ucred *cred, struct auditinfo *ai);
+int mac_proc_check_setaudit_addr(struct ucred *cred,
+ struct auditinfo_addr *aia);
+int mac_proc_check_setauid(struct ucred *cred, uid_t auid);
+int mac_proc_check_setegid(struct proc *p, struct ucred *cred,
+ gid_t egid);
+int mac_proc_check_seteuid(struct proc *p, struct ucred *cred,
+ uid_t euid);
+int mac_proc_check_setgid(struct proc *p, struct ucred *cred,
+ gid_t gid);
+int mac_proc_check_setgroups(struct proc *p, struct ucred *cred,
+ int ngroups, gid_t *gidset);
+int mac_proc_check_setregid(struct proc *p, struct ucred *cred,
+ gid_t rgid, gid_t egid);
+int mac_proc_check_setresgid(struct proc *p, struct ucred *cred,
+ gid_t rgid, gid_t egid, gid_t sgid);
+int mac_proc_check_setresuid(struct proc *p, struct ucred *cred,
+ uid_t ruid, uid_t euid, uid_t suid);
+int mac_proc_check_setreuid(struct proc *p, struct ucred *cred,
+ uid_t ruid, uid_t euid);
+int mac_proc_check_setuid(struct proc *p, struct ucred *cred,
+ uid_t uid);
+int mac_proc_check_signal(struct ucred *cred, struct proc *p,
+ int signum);
+int mac_proc_check_wait(struct ucred *cred, struct proc *p);
+void mac_proc_destroy(struct proc *);
+void mac_proc_init(struct proc *);
+void mac_proc_vm_revoke(struct thread *td);
+int mac_execve_enter(struct image_params *imgp, struct mac *mac_p);
+void mac_execve_exit(struct image_params *imgp);
+void mac_execve_interpreter_enter(struct vnode *interpvp,
+ struct label **interplabel);
+void mac_execve_interpreter_exit(struct label *interpvplabel);
+
+int mac_socket_check_accept(struct ucred *cred, struct socket *so);
+int mac_socket_check_bind(struct ucred *cred, struct socket *so,
+ struct sockaddr *sa);
+int mac_socket_check_connect(struct ucred *cred, struct socket *so,
+ struct sockaddr *sa);
+int mac_socket_check_create(struct ucred *cred, int domain, int type,
+ int proto);
+int mac_socket_check_deliver(struct socket *so, struct mbuf *m);
+int mac_socket_check_listen(struct ucred *cred, struct socket *so);
+int mac_socket_check_poll(struct ucred *cred, struct socket *so);
+int mac_socket_check_receive(struct ucred *cred, struct socket *so);
+int mac_socket_check_send(struct ucred *cred, struct socket *so);
+int mac_socket_check_stat(struct ucred *cred, struct socket *so);
+int mac_socket_check_visible(struct ucred *cred, struct socket *so);
+void mac_socket_create_mbuf(struct socket *so, struct mbuf *m);
+void mac_socket_create(struct ucred *cred, struct socket *so);
+void mac_socket_destroy(struct socket *);
+int mac_socket_init(struct socket *, int);
+void mac_socket_newconn(struct socket *oldso, struct socket *newso);
+int mac_getsockopt_label(struct ucred *cred, struct socket *so,
+ struct mac *extmac);
+int mac_getsockopt_peerlabel(struct ucred *cred, struct socket *so,
+ struct mac *extmac);
+int mac_setsockopt_label(struct ucred *cred, struct socket *so,
+ struct mac *extmac);
+
+void mac_socketpeer_set_from_mbuf(struct mbuf *m, struct socket *so);
+void mac_socketpeer_set_from_socket(struct socket *oldso,
+ struct socket *newso);
+
+void mac_syncache_create(struct label *l, struct inpcb *inp);
+void mac_syncache_create_mbuf(struct label *l, struct mbuf *m);
+void mac_syncache_destroy(struct label **l);
+int mac_syncache_init(struct label **l);
+
+int mac_system_check_acct(struct ucred *cred, struct vnode *vp);
+int mac_system_check_audit(struct ucred *cred, void *record, int length);
+int mac_system_check_auditctl(struct ucred *cred, struct vnode *vp);
+int mac_system_check_auditon(struct ucred *cred, int cmd);
+int mac_system_check_reboot(struct ucred *cred, int howto);
+int mac_system_check_swapon(struct ucred *cred, struct vnode *vp);
+int mac_system_check_swapoff(struct ucred *cred, struct vnode *vp);
+int mac_system_check_sysctl(struct ucred *cred, struct sysctl_oid *oidp,
+ void *arg1, int arg2, struct sysctl_req *req);
+
+void mac_sysvmsg_cleanup(struct msg *msgptr);
+void mac_sysvmsg_create(struct ucred *cred, struct msqid_kernel *msqkptr,
+ struct msg *msgptr);
+void mac_sysvmsg_destroy(struct msg *);
+void mac_sysvmsg_init(struct msg *);
+
+int mac_sysvmsq_check_msgmsq(struct ucred *cred, struct msg *msgptr,
+ struct msqid_kernel *msqkptr);
+int mac_sysvmsq_check_msgrcv(struct ucred *cred, struct msg *msgptr);
+int mac_sysvmsq_check_msgrmid(struct ucred *cred, struct msg *msgptr);
+int mac_sysvmsq_check_msqctl(struct ucred *cred,
+ struct msqid_kernel *msqkptr, int cmd);
+int mac_sysvmsq_check_msqget(struct ucred *cred,
+ struct msqid_kernel *msqkptr);
+int mac_sysvmsq_check_msqrcv(struct ucred *cred,
+ struct msqid_kernel *msqkptr);
+int mac_sysvmsq_check_msqsnd(struct ucred *cred,
+ struct msqid_kernel *msqkptr);
+void mac_sysvmsq_cleanup(struct msqid_kernel *msqkptr);
+void mac_sysvmsq_create(struct ucred *cred, struct msqid_kernel *msqkptr);
+void mac_sysvmsq_destroy(struct msqid_kernel *);
+void mac_sysvmsq_init(struct msqid_kernel *);
+
+int mac_sysvsem_check_semctl(struct ucred *cred,
+ struct semid_kernel *semakptr, int cmd);
+int mac_sysvsem_check_semget(struct ucred *cred,
+ struct semid_kernel *semakptr);
+int mac_sysvsem_check_semop(struct ucred *cred,
+ struct semid_kernel *semakptr, size_t accesstype);
+void mac_sysvsem_cleanup(struct semid_kernel *semakptr);
+void mac_sysvsem_create(struct ucred *cred,
+ struct semid_kernel *semakptr);
+void mac_sysvsem_destroy(struct semid_kernel *);
+void mac_sysvsem_init(struct semid_kernel *);
+
+int mac_sysvshm_check_shmat(struct ucred *cred,
+ struct shmid_kernel *shmsegptr, int shmflg);
+int mac_sysvshm_check_shmctl(struct ucred *cred,
+ struct shmid_kernel *shmsegptr, int cmd);
+int mac_sysvshm_check_shmdt(struct ucred *cred,
+ struct shmid_kernel *shmsegptr);
+int mac_sysvshm_check_shmget(struct ucred *cred,
+ struct shmid_kernel *shmsegptr, int shmflg);
+void mac_sysvshm_cleanup(struct shmid_kernel *shmsegptr);
+void mac_sysvshm_create(struct ucred *cred,
+ struct shmid_kernel *shmsegptr);
+void mac_sysvshm_destroy(struct shmid_kernel *);
+void mac_sysvshm_init(struct shmid_kernel *);
+
+void mac_thread_userret(struct thread *td);
+
+int mac_vnode_associate_extattr(struct mount *mp, struct vnode *vp);
+void mac_vnode_associate_singlelabel(struct mount *mp, struct vnode *vp);
+int mac_vnode_check_access(struct ucred *cred, struct vnode *vp,
+ accmode_t accmode);
+int mac_vnode_check_chdir(struct ucred *cred, struct vnode *dvp);
+int mac_vnode_check_chroot(struct ucred *cred, struct vnode *dvp);
+int mac_vnode_check_create(struct ucred *cred, struct vnode *dvp,
+ struct componentname *cnp, struct vattr *vap);
+int mac_vnode_check_deleteacl(struct ucred *cred, struct vnode *vp,
+ acl_type_t type);
+int mac_vnode_check_deleteextattr(struct ucred *cred, struct vnode *vp,
+ int attrnamespace, const char *name);
+int mac_vnode_check_exec(struct ucred *cred, struct vnode *vp,
+ struct image_params *imgp);
+int mac_vnode_check_getacl(struct ucred *cred, struct vnode *vp,
+ acl_type_t type);
+int mac_vnode_check_getextattr(struct ucred *cred, struct vnode *vp,
+ int attrnamespace, const char *name, struct uio *uio);
+int mac_vnode_check_link(struct ucred *cred, struct vnode *dvp,
+ struct vnode *vp, struct componentname *cnp);
+int mac_vnode_check_listextattr(struct ucred *cred, struct vnode *vp,
+ int attrnamespace);
+int mac_vnode_check_lookup(struct ucred *cred, struct vnode *dvp,
+ struct componentname *cnp);
+int mac_vnode_check_mmap(struct ucred *cred, struct vnode *vp, int prot,
+ int flags);
+int mac_vnode_check_mprotect(struct ucred *cred, struct vnode *vp,
+ int prot);
+int mac_vnode_check_open(struct ucred *cred, struct vnode *vp,
+ accmode_t accmode);
+int mac_vnode_check_poll(struct ucred *active_cred,
+ struct ucred *file_cred, struct vnode *vp);
+int mac_vnode_check_read(struct ucred *active_cred,
+ struct ucred *file_cred, struct vnode *vp);
+int mac_vnode_check_readdir(struct ucred *cred, struct vnode *vp);
+int mac_vnode_check_readlink(struct ucred *cred, struct vnode *vp);
+int mac_vnode_check_rename_from(struct ucred *cred, struct vnode *dvp,
+ struct vnode *vp, struct componentname *cnp);
+int mac_vnode_check_rename_to(struct ucred *cred, struct vnode *dvp,
+ struct vnode *vp, int samedir, struct componentname *cnp);
+int mac_vnode_check_revoke(struct ucred *cred, struct vnode *vp);
+int mac_vnode_check_setacl(struct ucred *cred, struct vnode *vp,
+ acl_type_t type, struct acl *acl);
+int mac_vnode_check_setextattr(struct ucred *cred, struct vnode *vp,
+ int attrnamespace, const char *name, struct uio *uio);
+int mac_vnode_check_setflags(struct ucred *cred, struct vnode *vp,
+ u_long flags);
+int mac_vnode_check_setmode(struct ucred *cred, struct vnode *vp,
+ mode_t mode);
+int mac_vnode_check_setowner(struct ucred *cred, struct vnode *vp,
+ uid_t uid, gid_t gid);
+int mac_vnode_check_setutimes(struct ucred *cred, struct vnode *vp,
+ struct timespec atime, struct timespec mtime);
+int mac_vnode_check_stat(struct ucred *active_cred,
+ struct ucred *file_cred, struct vnode *vp);
+int mac_vnode_check_unlink(struct ucred *cred, struct vnode *dvp,
+ struct vnode *vp, struct componentname *cnp);
+int mac_vnode_check_write(struct ucred *active_cred,
+ struct ucred *file_cred, struct vnode *vp);
+void mac_vnode_copy_label(struct label *, struct label *);
+void mac_vnode_init(struct vnode *);
+int mac_vnode_create_extattr(struct ucred *cred, struct mount *mp,
+ struct vnode *dvp, struct vnode *vp, struct componentname *cnp);
+void mac_vnode_destroy(struct vnode *);
+void mac_vnode_execve_transition(struct ucred *oldcred,
+ struct ucred *newcred, struct vnode *vp,
+ struct label *interpvplabel, struct image_params *imgp);
+int mac_vnode_execve_will_transition(struct ucred *cred,
+ struct vnode *vp, struct label *interpvplabel,
+ struct image_params *imgp);
+void mac_vnode_relabel(struct ucred *cred, struct vnode *vp,
+ struct label *newlabel);
+
+/*
+ * Calls to help various file systems implement labeling functionality using
+ * their existing EA implementation.
+ */
+int vop_stdsetlabel_ea(struct vop_setlabel_args *ap);
+
+#endif /* !_SECURITY_MAC_MAC_FRAMEWORK_H_ */
diff --git a/sys/security/mac/mac_inet.c b/sys/security/mac/mac_inet.c
new file mode 100644
index 0000000..b11f5b7
--- /dev/null
+++ b/sys/security/mac/mac_inet.c
@@ -0,0 +1,425 @@
+/*-
+ * Copyright (c) 1999-2002, 2007 Robert N. M. Watson
+ * Copyright (c) 2001 Ilmar S. Habibulin
+ * Copyright (c) 2001-2004 Networks Associates Technology, Inc.
+ * Copyright (c) 2006 SPARTA, Inc.
+ * Copyright (c) 2008 Apple Inc.
+ * All rights reserved.
+ *
+ * This software was developed by Robert Watson and Ilmar Habibulin for the
+ * TrustedBSD Project.
+ *
+ * This software was developed for the FreeBSD Project in part by Network
+ * Associates Laboratories, the Security Research Division of Network
+ * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"),
+ * as part of the DARPA CHATS research program.
+ *
+ * This software was enhanced by SPARTA ISSO under SPAWAR contract
+ * N66001-04-C-6019 ("SEFOS").
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "opt_mac.h"
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/mutex.h>
+#include <sys/sbuf.h>
+#include <sys/systm.h>
+#include <sys/mount.h>
+#include <sys/file.h>
+#include <sys/namei.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/sysctl.h>
+
+#include <net/if.h>
+#include <net/if_var.h>
+
+#include <netinet/in.h>
+#include <netinet/in_pcb.h>
+#include <netinet/ip_var.h>
+
+#include <security/mac/mac_framework.h>
+#include <security/mac/mac_internal.h>
+#include <security/mac/mac_policy.h>
+
+static struct label *
+mac_inpcb_label_alloc(int flag)
+{
+ struct label *label;
+ int error;
+
+ label = mac_labelzone_alloc(flag);
+ if (label == NULL)
+ return (NULL);
+ MAC_CHECK(inpcb_init_label, label, flag);
+ if (error) {
+ MAC_PERFORM(inpcb_destroy_label, label);
+ mac_labelzone_free(label);
+ return (NULL);
+ }
+ return (label);
+}
+
+int
+mac_inpcb_init(struct inpcb *inp, int flag)
+{
+
+ if (mac_labeled & MPC_OBJECT_INPCB) {
+ inp->inp_label = mac_inpcb_label_alloc(flag);
+ if (inp->inp_label == NULL)
+ return (ENOMEM);
+ } else
+ inp->inp_label = NULL;
+ return (0);
+}
+
+static struct label *
+mac_ipq_label_alloc(int flag)
+{
+ struct label *label;
+ int error;
+
+ label = mac_labelzone_alloc(flag);
+ if (label == NULL)
+ return (NULL);
+
+ MAC_CHECK(ipq_init_label, label, flag);
+ if (error) {
+ MAC_PERFORM(ipq_destroy_label, label);
+ mac_labelzone_free(label);
+ return (NULL);
+ }
+ return (label);
+}
+
+int
+mac_ipq_init(struct ipq *q, int flag)
+{
+
+ if (mac_labeled & MPC_OBJECT_IPQ) {
+ q->ipq_label = mac_ipq_label_alloc(flag);
+ if (q->ipq_label == NULL)
+ return (ENOMEM);
+ } else
+ q->ipq_label = NULL;
+ return (0);
+}
+
+static void
+mac_inpcb_label_free(struct label *label)
+{
+
+ MAC_PERFORM(inpcb_destroy_label, label);
+ mac_labelzone_free(label);
+}
+
+void
+mac_inpcb_destroy(struct inpcb *inp)
+{
+
+ if (inp->inp_label != NULL) {
+ mac_inpcb_label_free(inp->inp_label);
+ inp->inp_label = NULL;
+ }
+}
+
+static void
+mac_ipq_label_free(struct label *label)
+{
+
+ MAC_PERFORM(ipq_destroy_label, label);
+ mac_labelzone_free(label);
+}
+
+void
+mac_ipq_destroy(struct ipq *q)
+{
+
+ if (q->ipq_label != NULL) {
+ mac_ipq_label_free(q->ipq_label);
+ q->ipq_label = NULL;
+ }
+}
+
+void
+mac_inpcb_create(struct socket *so, struct inpcb *inp)
+{
+
+ MAC_PERFORM(inpcb_create, so, so->so_label, inp, inp->inp_label);
+}
+
+void
+mac_ipq_reassemble(struct ipq *q, struct mbuf *m)
+{
+ struct label *label;
+
+ label = mac_mbuf_to_label(m);
+
+ MAC_PERFORM(ipq_reassemble, q, q->ipq_label, m, label);
+}
+
+void
+mac_netinet_fragment(struct mbuf *m, struct mbuf *frag)
+{
+ struct label *mlabel, *fraglabel;
+
+ mlabel = mac_mbuf_to_label(m);
+ fraglabel = mac_mbuf_to_label(frag);
+
+ MAC_PERFORM(netinet_fragment, m, mlabel, frag, fraglabel);
+}
+
+void
+mac_ipq_create(struct mbuf *m, struct ipq *q)
+{
+ struct label *label;
+
+ label = mac_mbuf_to_label(m);
+
+ MAC_PERFORM(ipq_create, m, label, q, q->ipq_label);
+}
+
+void
+mac_inpcb_create_mbuf(struct inpcb *inp, struct mbuf *m)
+{
+ struct label *mlabel;
+
+ INP_LOCK_ASSERT(inp);
+ mlabel = mac_mbuf_to_label(m);
+
+ MAC_PERFORM(inpcb_create_mbuf, inp, inp->inp_label, m, mlabel);
+}
+
+int
+mac_ipq_match(struct mbuf *m, struct ipq *q)
+{
+ struct label *label;
+ int result;
+
+ label = mac_mbuf_to_label(m);
+
+ result = 1;
+ MAC_BOOLEAN(ipq_match, &&, m, label, q, q->ipq_label);
+
+ return (result);
+}
+
+void
+mac_netinet_arp_send(struct ifnet *ifp, struct mbuf *m)
+{
+ struct label *mlabel;
+
+ mlabel = mac_mbuf_to_label(m);
+
+ MAC_IFNET_LOCK(ifp);
+ MAC_PERFORM(netinet_arp_send, ifp, ifp->if_label, m, mlabel);
+ MAC_IFNET_UNLOCK(ifp);
+}
+
+void
+mac_netinet_icmp_reply(struct mbuf *mrecv, struct mbuf *msend)
+{
+ struct label *mrecvlabel, *msendlabel;
+
+ mrecvlabel = mac_mbuf_to_label(mrecv);
+ msendlabel = mac_mbuf_to_label(msend);
+
+ MAC_PERFORM(netinet_icmp_reply, mrecv, mrecvlabel, msend,
+ msendlabel);
+}
+
+void
+mac_netinet_icmp_replyinplace(struct mbuf *m)
+{
+ struct label *label;
+
+ label = mac_mbuf_to_label(m);
+
+ MAC_PERFORM(netinet_icmp_replyinplace, m, label);
+}
+
+void
+mac_netinet_igmp_send(struct ifnet *ifp, struct mbuf *m)
+{
+ struct label *mlabel;
+
+ mlabel = mac_mbuf_to_label(m);
+
+ MAC_IFNET_LOCK(ifp);
+ MAC_PERFORM(netinet_igmp_send, ifp, ifp->if_label, m, mlabel);
+ MAC_IFNET_UNLOCK(ifp);
+}
+
+void
+mac_netinet_tcp_reply(struct mbuf *m)
+{
+ struct label *label;
+
+ label = mac_mbuf_to_label(m);
+
+ MAC_PERFORM(netinet_tcp_reply, m, label);
+}
+
+void
+mac_ipq_update(struct mbuf *m, struct ipq *q)
+{
+ struct label *label;
+
+ label = mac_mbuf_to_label(m);
+
+ MAC_PERFORM(ipq_update, m, label, q, q->ipq_label);
+}
+
+int
+mac_inpcb_check_deliver(struct inpcb *inp, struct mbuf *m)
+{
+ struct label *label;
+ int error;
+
+ M_ASSERTPKTHDR(m);
+
+ label = mac_mbuf_to_label(m);
+
+ MAC_CHECK(inpcb_check_deliver, inp, inp->inp_label, m, label);
+
+ return (error);
+}
+
+int
+mac_inpcb_check_visible(struct ucred *cred, struct inpcb *inp)
+{
+ int error;
+
+ INP_LOCK_ASSERT(inp);
+
+ MAC_CHECK(inpcb_check_visible, cred, inp, inp->inp_label);
+
+ return (error);
+}
+
+void
+mac_inpcb_sosetlabel(struct socket *so, struct inpcb *inp)
+{
+
+ INP_WLOCK_ASSERT(inp);
+ SOCK_LOCK_ASSERT(so);
+ MAC_PERFORM(inpcb_sosetlabel, so, so->so_label, inp, inp->inp_label);
+}
+
+void
+mac_netinet_firewall_reply(struct mbuf *mrecv, struct mbuf *msend)
+{
+ struct label *mrecvlabel, *msendlabel;
+
+ M_ASSERTPKTHDR(mrecv);
+ M_ASSERTPKTHDR(msend);
+
+ mrecvlabel = mac_mbuf_to_label(mrecv);
+ msendlabel = mac_mbuf_to_label(msend);
+
+ MAC_PERFORM(netinet_firewall_reply, mrecv, mrecvlabel, msend,
+ msendlabel);
+}
+
+void
+mac_netinet_firewall_send(struct mbuf *m)
+{
+ struct label *label;
+
+ M_ASSERTPKTHDR(m);
+ label = mac_mbuf_to_label(m);
+ MAC_PERFORM(netinet_firewall_send, m, label);
+}
+
+/*
+ * These functions really should be referencing the syncache structure
+ * instead of the label. However, due to some of the complexities associated
+ * with exposing this syncache structure we operate directly on it's label
+ * pointer. This should be OK since we aren't making any access control
+ * decisions within this code directly, we are merely allocating and copying
+ * label storage so we can properly initialize mbuf labels for any packets
+ * the syncache code might create.
+ */
+void
+mac_syncache_destroy(struct label **label)
+{
+
+ if (*label != NULL) {
+ MAC_PERFORM(syncache_destroy_label, *label);
+ mac_labelzone_free(*label);
+ *label = NULL;
+ }
+}
+
+int
+mac_syncache_init(struct label **label)
+{
+ int error;
+
+ if (mac_labeled & MPC_OBJECT_SYNCACHE) {
+ *label = mac_labelzone_alloc(M_NOWAIT);
+ if (*label == NULL)
+ return (ENOMEM);
+ /*
+ * Since we are holding the inpcb locks the policy can not
+ * allocate policy specific label storage using M_WAITOK. So
+ * we need to do a MAC_CHECK instead of the typical
+ * MAC_PERFORM so we can propagate allocation failures back
+ * to the syncache code.
+ */
+ MAC_CHECK(syncache_init_label, *label, M_NOWAIT);
+ if (error) {
+ MAC_PERFORM(syncache_destroy_label, *label);
+ mac_labelzone_free(*label);
+ }
+ return (error);
+ } else
+ *label = NULL;
+ return (0);
+}
+
+void
+mac_syncache_create(struct label *label, struct inpcb *inp)
+{
+
+ INP_WLOCK_ASSERT(inp);
+ MAC_PERFORM(syncache_create, label, inp);
+}
+
+void
+mac_syncache_create_mbuf(struct label *sc_label, struct mbuf *m)
+{
+ struct label *mlabel;
+
+ M_ASSERTPKTHDR(m);
+ mlabel = mac_mbuf_to_label(m);
+ MAC_PERFORM(syncache_create_mbuf, sc_label, m, mlabel);
+}
diff --git a/sys/security/mac/mac_inet6.c b/sys/security/mac/mac_inet6.c
new file mode 100644
index 0000000..068455b
--- /dev/null
+++ b/sys/security/mac/mac_inet6.c
@@ -0,0 +1,162 @@
+/*-
+ * Copyright (c) 2007-2008 Robert N. M. Watson
+ * All rights reserved.
+ *
+ * This software was developed by Robert Watson for the TrustedBSD Project.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "opt_mac.h"
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/mutex.h>
+#include <sys/sbuf.h>
+#include <sys/systm.h>
+#include <sys/mount.h>
+#include <sys/file.h>
+#include <sys/namei.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/sysctl.h>
+
+#include <net/if.h>
+#include <net/if_var.h>
+
+#include <netinet/in.h>
+#include <netinet/ip6.h>
+#include <netinet6/ip6_var.h>
+
+#include <security/mac/mac_framework.h>
+#include <security/mac/mac_internal.h>
+#include <security/mac/mac_policy.h>
+
+static struct label *
+mac_ip6q_label_alloc(int flag)
+{
+ struct label *label;
+ int error;
+
+ label = mac_labelzone_alloc(flag);
+ if (label == NULL)
+ return (NULL);
+
+ MAC_CHECK(ip6q_init_label, label, flag);
+ if (error) {
+ MAC_PERFORM(ip6q_destroy_label, label);
+ mac_labelzone_free(label);
+ return (NULL);
+ }
+ return (label);
+}
+
+int
+mac_ip6q_init(struct ip6q *q6, int flag)
+{
+
+ if (mac_labeled & MPC_OBJECT_IPQ) {
+ q6->ip6q_label = mac_ip6q_label_alloc(flag);
+ if (q6->ip6q_label == NULL)
+ return (ENOMEM);
+ } else
+ q6->ip6q_label = NULL;
+ return (0);
+}
+
+static void
+mac_ip6q_label_free(struct label *label)
+{
+
+ MAC_PERFORM(ip6q_destroy_label, label);
+ mac_labelzone_free(label);
+}
+
+void
+mac_ip6q_destroy(struct ip6q *q6)
+{
+
+ if (q6->ip6q_label != NULL) {
+ mac_ip6q_label_free(q6->ip6q_label);
+ q6->ip6q_label = NULL;
+ }
+}
+
+void
+mac_ip6q_reassemble(struct ip6q *q6, struct mbuf *m)
+{
+ struct label *label;
+
+ label = mac_mbuf_to_label(m);
+
+ MAC_PERFORM(ip6q_reassemble, q6, q6->ip6q_label, m, label);
+}
+
+void
+mac_ip6q_create(struct mbuf *m, struct ip6q *q6)
+{
+ struct label *label;
+
+ label = mac_mbuf_to_label(m);
+
+ MAC_PERFORM(ip6q_create, m, label, q6, q6->ip6q_label);
+}
+
+int
+mac_ip6q_match(struct mbuf *m, struct ip6q *q6)
+{
+ struct label *label;
+ int result;
+
+ label = mac_mbuf_to_label(m);
+
+ result = 1;
+ MAC_BOOLEAN(ip6q_match, &&, m, label, q6, q6->ip6q_label);
+
+ return (result);
+}
+
+void
+mac_ip6q_update(struct mbuf *m, struct ip6q *q6)
+{
+ struct label *label;
+
+ label = mac_mbuf_to_label(m);
+
+ MAC_PERFORM(ip6q_update, m, label, q6, q6->ip6q_label);
+}
+
+void
+mac_netinet6_nd6_send(struct ifnet *ifp, struct mbuf *m)
+{
+ struct label *mlabel;
+
+ mlabel = mac_mbuf_to_label(m);
+
+ MAC_PERFORM(netinet6_nd6_send, ifp, ifp->if_label, m, mlabel);
+}
diff --git a/sys/security/mac/mac_internal.h b/sys/security/mac/mac_internal.h
new file mode 100644
index 0000000..23da90a
--- /dev/null
+++ b/sys/security/mac/mac_internal.h
@@ -0,0 +1,345 @@
+/*-
+ * Copyright (c) 1999-2002, 2006 Robert N. M. Watson
+ * Copyright (c) 2001 Ilmar S. Habibulin
+ * Copyright (c) 2001-2004 Networks Associates Technology, Inc.
+ * Copyright (c) 2006 nCircle Network Security, Inc.
+ * Copyright (c) 2006 SPARTA, Inc.
+ * All rights reserved.
+ *
+ * This software was developed by Robert Watson and Ilmar Habibulin for the
+ * TrustedBSD Project.
+ *
+ * This software was developed for the FreeBSD Project in part by Network
+ * Associates Laboratories, the Security Research Division of Network
+ * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"),
+ * as part of the DARPA CHATS research program.
+ *
+ * This software was developed by Robert N. M. Watson for the TrustedBSD
+ * Project under contract to nCircle Network Security, Inc.
+ *
+ * This software was enhanced by SPARTA ISSO under SPAWAR contract
+ * N66001-04-C-6019 ("SEFOS").
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _SECURITY_MAC_MAC_INTERNAL_H_
+#define _SECURITY_MAC_MAC_INTERNAL_H_
+
+#ifndef _KERNEL
+#error "no user-serviceable parts inside"
+#endif
+
+/*
+ * MAC Framework sysctl namespace.
+ */
+#ifdef SYSCTL_DECL
+SYSCTL_DECL(_security_mac);
+#endif /* SYSCTL_DECL */
+
+/*
+ * MAC Framework global types and typedefs.
+ */
+LIST_HEAD(mac_policy_list_head, mac_policy_conf);
+#ifdef MALLOC_DECLARE
+MALLOC_DECLARE(M_MACTEMP);
+#endif
+
+/*
+ * MAC labels -- in-kernel storage format.
+ *
+ * In general, struct label pointers are embedded in kernel data structures
+ * representing objects that may be labeled (and protected). Struct label is
+ * opaque to both kernel services that invoke the MAC Framework and MAC
+ * policy modules. In particular, we do not wish to encode the layout of the
+ * label structure into any ABIs. Historically, the slot array contained
+ * unions of {long, void} but now contains uintptr_t.
+ */
+#define MAC_MAX_SLOTS 4
+#define MAC_FLAG_INITIALIZED 0x0000001 /* Is initialized for use. */
+struct label {
+ int l_flags;
+ intptr_t l_perpolicy[MAC_MAX_SLOTS];
+};
+
+/*
+ * MAC Framework global variables.
+ */
+extern struct mac_policy_list_head mac_policy_list;
+extern struct mac_policy_list_head mac_static_policy_list;
+extern uint64_t mac_labeled;
+extern struct mtx mac_ifnet_mtx;
+
+/*
+ * MAC Framework infrastructure functions.
+ */
+int mac_error_select(int error1, int error2);
+
+void mac_policy_grab_exclusive(void);
+void mac_policy_assert_exclusive(void);
+void mac_policy_release_exclusive(void);
+void mac_policy_list_busy(void);
+int mac_policy_list_conditional_busy(void);
+void mac_policy_list_unbusy(void);
+
+struct label *mac_labelzone_alloc(int flags);
+void mac_labelzone_free(struct label *label);
+void mac_labelzone_init(void);
+
+void mac_init_label(struct label *label);
+void mac_destroy_label(struct label *label);
+int mac_check_structmac_consistent(struct mac *mac);
+int mac_allocate_slot(void);
+
+#define MAC_IFNET_LOCK(ifp) mtx_lock(&mac_ifnet_mtx)
+#define MAC_IFNET_UNLOCK(ifp) mtx_unlock(&mac_ifnet_mtx)
+
+/*
+ * MAC Framework per-object type functions. It's not yet clear how the
+ * namespaces, etc, should work for these, so for now, sort by object type.
+ */
+struct label *mac_cred_label_alloc(void);
+void mac_cred_label_free(struct label *label);
+struct label *mac_pipe_label_alloc(void);
+void mac_pipe_label_free(struct label *label);
+struct label *mac_socket_label_alloc(int flag);
+void mac_socket_label_free(struct label *label);
+struct label *mac_vnode_label_alloc(void);
+void mac_vnode_label_free(struct label *label);
+
+int mac_cred_check_relabel(struct ucred *cred, struct label *newlabel);
+int mac_cred_externalize_label(struct label *label, char *elements,
+ char *outbuf, size_t outbuflen);
+int mac_cred_internalize_label(struct label *label, char *string);
+void mac_cred_relabel(struct ucred *cred, struct label *newlabel);
+
+struct label *mac_mbuf_to_label(struct mbuf *m);
+
+void mac_pipe_copy_label(struct label *src, struct label *dest);
+int mac_pipe_externalize_label(struct label *label, char *elements,
+ char *outbuf, size_t outbuflen);
+int mac_pipe_internalize_label(struct label *label, char *string);
+
+int mac_socket_label_set(struct ucred *cred, struct socket *so,
+ struct label *label);
+void mac_socket_copy_label(struct label *src, struct label *dest);
+int mac_socket_externalize_label(struct label *label, char *elements,
+ char *outbuf, size_t outbuflen);
+int mac_socket_internalize_label(struct label *label, char *string);
+
+int mac_vnode_externalize_label(struct label *label, char *elements,
+ char *outbuf, size_t outbuflen);
+int mac_vnode_internalize_label(struct label *label, char *string);
+void mac_vnode_check_mmap_downgrade(struct ucred *cred, struct vnode *vp,
+ int *prot);
+int vn_setlabel(struct vnode *vp, struct label *intlabel,
+ struct ucred *cred);
+
+/*
+ * MAC_CHECK performs the designated check by walking the policy module list
+ * and checking with each as to how it feels about the request. Note that it
+ * returns its value via 'error' in the scope of the caller.
+ */
+#define MAC_CHECK(check, args...) do { \
+ struct mac_policy_conf *mpc; \
+ int entrycount; \
+ \
+ error = 0; \
+ LIST_FOREACH(mpc, &mac_static_policy_list, mpc_list) { \
+ if (mpc->mpc_ops->mpo_ ## check != NULL) \
+ error = mac_error_select( \
+ mpc->mpc_ops->mpo_ ## check (args), \
+ error); \
+ } \
+ if ((entrycount = mac_policy_list_conditional_busy()) != 0) { \
+ LIST_FOREACH(mpc, &mac_policy_list, mpc_list) { \
+ if (mpc->mpc_ops->mpo_ ## check != NULL) \
+ error = mac_error_select( \
+ mpc->mpc_ops->mpo_ ## check (args), \
+ error); \
+ } \
+ mac_policy_list_unbusy(); \
+ } \
+} while (0)
+
+/*
+ * MAC_GRANT performs the designated check by walking the policy module list
+ * and checking with each as to how it feels about the request. Unlike
+ * MAC_CHECK, it grants if any policies return '0', and otherwise returns
+ * EPERM. Note that it returns its value via 'error' in the scope of the
+ * caller.
+ */
+#define MAC_GRANT(check, args...) do { \
+ struct mac_policy_conf *mpc; \
+ int entrycount; \
+ \
+ error = EPERM; \
+ LIST_FOREACH(mpc, &mac_static_policy_list, mpc_list) { \
+ if (mpc->mpc_ops->mpo_ ## check != NULL) { \
+ if (mpc->mpc_ops->mpo_ ## check(args) == 0) \
+ error = 0; \
+ } \
+ } \
+ if ((entrycount = mac_policy_list_conditional_busy()) != 0) { \
+ LIST_FOREACH(mpc, &mac_policy_list, mpc_list) { \
+ if (mpc->mpc_ops->mpo_ ## check != NULL) { \
+ if (mpc->mpc_ops->mpo_ ## check (args) \
+ == 0) \
+ error = 0; \
+ } \
+ } \
+ mac_policy_list_unbusy(); \
+ } \
+} while (0)
+
+/*
+ * MAC_BOOLEAN performs the designated boolean composition by walking the
+ * module list, invoking each instance of the operation, and combining the
+ * results using the passed C operator. Note that it returns its value via
+ * 'result' in the scope of the caller, which should be initialized by the
+ * caller in a meaningful way to get a meaningful result.
+ */
+#define MAC_BOOLEAN(operation, composition, args...) do { \
+ struct mac_policy_conf *mpc; \
+ int entrycount; \
+ \
+ LIST_FOREACH(mpc, &mac_static_policy_list, mpc_list) { \
+ if (mpc->mpc_ops->mpo_ ## operation != NULL) \
+ result = result composition \
+ mpc->mpc_ops->mpo_ ## operation (args); \
+ } \
+ if ((entrycount = mac_policy_list_conditional_busy()) != 0) { \
+ LIST_FOREACH(mpc, &mac_policy_list, mpc_list) { \
+ if (mpc->mpc_ops->mpo_ ## operation != NULL) \
+ result = result composition \
+ mpc->mpc_ops->mpo_ ## operation \
+ (args); \
+ } \
+ mac_policy_list_unbusy(); \
+ } \
+} while (0)
+
+/*
+ * MAC_EXTERNALIZE queries each policy to see if it can generate an
+ * externalized version of a label element by name. Policies declare whether
+ * they have matched a particular element name, parsed from the string by
+ * MAC_EXTERNALIZE, and an error is returned if any element is matched by no
+ * policy.
+ */
+#define MAC_EXTERNALIZE(type, label, elementlist, outbuf, \
+ outbuflen) do { \
+ int claimed, first, ignorenotfound, savedlen; \
+ char *element_name, *element_temp; \
+ struct sbuf sb; \
+ \
+ error = 0; \
+ first = 1; \
+ sbuf_new(&sb, outbuf, outbuflen, SBUF_FIXEDLEN); \
+ element_temp = elementlist; \
+ while ((element_name = strsep(&element_temp, ",")) != NULL) { \
+ if (element_name[0] == '?') { \
+ element_name++; \
+ ignorenotfound = 1; \
+ } else \
+ ignorenotfound = 0; \
+ savedlen = sbuf_len(&sb); \
+ if (first) \
+ error = sbuf_printf(&sb, "%s/", element_name); \
+ else \
+ error = sbuf_printf(&sb, ",%s/", element_name); \
+ if (error == -1) { \
+ error = EINVAL; /* XXX: E2BIG? */ \
+ break; \
+ } \
+ claimed = 0; \
+ MAC_CHECK(type ## _externalize_label, label, \
+ element_name, &sb, &claimed); \
+ if (error) \
+ break; \
+ if (claimed == 0 && ignorenotfound) { \
+ /* Revert last label name. */ \
+ sbuf_setpos(&sb, savedlen); \
+ } else if (claimed != 1) { \
+ error = EINVAL; /* XXX: ENOLABEL? */ \
+ break; \
+ } else { \
+ first = 0; \
+ } \
+ } \
+ sbuf_finish(&sb); \
+} while (0)
+
+/*
+ * MAC_INTERNALIZE presents parsed element names and data to each policy to
+ * see if any is willing to claim it and internalize the label data. If no
+ * policies match, an error is returned.
+ */
+#define MAC_INTERNALIZE(type, label, instring) do { \
+ char *element, *element_name, *element_data; \
+ int claimed; \
+ \
+ error = 0; \
+ element = instring; \
+ while ((element_name = strsep(&element, ",")) != NULL) { \
+ element_data = element_name; \
+ element_name = strsep(&element_data, "/"); \
+ if (element_data == NULL) { \
+ error = EINVAL; \
+ break; \
+ } \
+ claimed = 0; \
+ MAC_CHECK(type ## _internalize_label, label, \
+ element_name, element_data, &claimed); \
+ if (error) \
+ break; \
+ if (claimed != 1) { \
+ /* XXXMAC: Another error here? */ \
+ error = EINVAL; \
+ break; \
+ } \
+ } \
+} while (0)
+
+/*
+ * MAC_PERFORM performs the designated operation by walking the policy module
+ * list and invoking that operation for each policy.
+ */
+#define MAC_PERFORM(operation, args...) do { \
+ struct mac_policy_conf *mpc; \
+ int entrycount; \
+ \
+ LIST_FOREACH(mpc, &mac_static_policy_list, mpc_list) { \
+ if (mpc->mpc_ops->mpo_ ## operation != NULL) \
+ mpc->mpc_ops->mpo_ ## operation (args); \
+ } \
+ if ((entrycount = mac_policy_list_conditional_busy()) != 0) { \
+ LIST_FOREACH(mpc, &mac_policy_list, mpc_list) { \
+ if (mpc->mpc_ops->mpo_ ## operation != NULL) \
+ mpc->mpc_ops->mpo_ ## operation (args); \
+ } \
+ mac_policy_list_unbusy(); \
+ } \
+} while (0)
+
+#endif /* !_SECURITY_MAC_MAC_INTERNAL_H_ */
diff --git a/sys/security/mac/mac_label.c b/sys/security/mac/mac_label.c
new file mode 100644
index 0000000..c058653
--- /dev/null
+++ b/sys/security/mac/mac_label.c
@@ -0,0 +1,151 @@
+/*-
+ * Copyright (c) 2003-2004 Networks Associates Technology, Inc.
+ * Copyright (c) 2007 Robert N. M. Watson
+ * All rights reserved.
+ *
+ * This software was developed for the FreeBSD Project in part by Network
+ * Associates Laboratories, the Security Research Division of Network
+ * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"),
+ * as part of the DARPA CHATS research program.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "opt_mac.h"
+
+#include <sys/param.h>
+#include <sys/module.h>
+#include <sys/sysctl.h>
+#include <sys/systm.h>
+
+#include <vm/uma.h>
+
+#include <security/mac/mac_framework.h>
+#include <security/mac/mac_internal.h>
+#include <security/mac/mac_policy.h>
+
+/*
+ * zone_label is the UMA zone from which most labels are allocated. Label
+ * structures are initialized to zero bytes so that policies see a NULL/0
+ * slot on first use, even if the policy is loaded after the label is
+ * allocated for an object.
+ */
+static uma_zone_t zone_label;
+
+static int mac_labelzone_ctor(void *mem, int size, void *arg, int flags);
+static void mac_labelzone_dtor(void *mem, int size, void *arg);
+
+void
+mac_labelzone_init(void)
+{
+
+ zone_label = uma_zcreate("MAC labels", sizeof(struct label),
+ mac_labelzone_ctor, mac_labelzone_dtor, NULL, NULL,
+ UMA_ALIGN_PTR, 0);
+}
+
+/*
+ * mac_init_label() and mac_destroy_label() are exported so that they can be
+ * used in mbuf tag initialization, where labels are not slab allocated from
+ * the zone_label zone.
+ */
+void
+mac_init_label(struct label *label)
+{
+
+ bzero(label, sizeof(*label));
+ label->l_flags = MAC_FLAG_INITIALIZED;
+}
+
+void
+mac_destroy_label(struct label *label)
+{
+
+ KASSERT(label->l_flags & MAC_FLAG_INITIALIZED,
+ ("destroying uninitialized label"));
+
+#ifdef DIAGNOSTIC
+ bzero(label, sizeof(*label));
+#else
+ label->l_flags &= ~MAC_FLAG_INITIALIZED;
+#endif
+}
+
+
+static int
+mac_labelzone_ctor(void *mem, int size, void *arg, int flags)
+{
+ struct label *label;
+
+ KASSERT(size == sizeof(*label), ("mac_labelzone_ctor: wrong size\n"));
+ label = mem;
+ mac_init_label(label);
+ return (0);
+}
+
+static void
+mac_labelzone_dtor(void *mem, int size, void *arg)
+{
+ struct label *label;
+
+ KASSERT(size == sizeof(*label), ("mac_labelzone_dtor: wrong size\n"));
+ label = mem;
+ mac_destroy_label(label);
+}
+
+struct label *
+mac_labelzone_alloc(int flags)
+{
+
+ return (uma_zalloc(zone_label, flags));
+}
+
+void
+mac_labelzone_free(struct label *label)
+{
+
+ uma_zfree(zone_label, label);
+}
+
+/*
+ * Functions used by policy modules to get and set label values.
+ */
+intptr_t
+mac_label_get(struct label *l, int slot)
+{
+
+ KASSERT(l != NULL, ("mac_label_get: NULL label"));
+
+ return (l->l_perpolicy[slot]);
+}
+
+void
+mac_label_set(struct label *l, int slot, intptr_t v)
+{
+
+ KASSERT(l != NULL, ("mac_label_set: NULL label"));
+
+ l->l_perpolicy[slot] = v;
+}
diff --git a/sys/security/mac/mac_net.c b/sys/security/mac/mac_net.c
new file mode 100644
index 0000000..8e8afea
--- /dev/null
+++ b/sys/security/mac/mac_net.c
@@ -0,0 +1,460 @@
+/*-
+ * Copyright (c) 1999-2002 Robert N. M. Watson
+ * Copyright (c) 2001 Ilmar S. Habibulin
+ * Copyright (c) 2001-2004 Networks Associates Technology, Inc.
+ * Copyright (c) 2006 SPARTA, Inc.
+ * Copyright (c) 2008 Apple Inc.
+ * All rights reserved.
+ *
+ * This software was developed by Robert Watson and Ilmar Habibulin for the
+ * TrustedBSD Project.
+ *
+ * This software was enhanced by SPARTA ISSO under SPAWAR contract
+ * N66001-04-C-6019 ("SEFOS").
+ *
+ * This software was developed for the FreeBSD Project in part by Network
+ * Associates Laboratories, the Security Research Division of Network
+ * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"),
+ * as part of the DARPA CHATS research program.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "opt_mac.h"
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/mutex.h>
+#include <sys/mac.h>
+#include <sys/priv.h>
+#include <sys/sbuf.h>
+#include <sys/systm.h>
+#include <sys/mount.h>
+#include <sys/file.h>
+#include <sys/namei.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/sysctl.h>
+
+#include <net/bpfdesc.h>
+#include <net/if.h>
+#include <net/if_var.h>
+
+#include <security/mac/mac_framework.h>
+#include <security/mac/mac_internal.h>
+#include <security/mac/mac_policy.h>
+
+/*
+ * XXXRW: struct ifnet locking is incomplete in the network code, so we use
+ * our own global mutex for struct ifnet. Non-ideal, but should help in the
+ * SMP environment.
+ */
+struct mtx mac_ifnet_mtx;
+MTX_SYSINIT(mac_ifnet_mtx, &mac_ifnet_mtx, "mac_ifnet", MTX_DEF);
+
+/*
+ * Retrieve the label associated with an mbuf by searching for the tag.
+ * Depending on the value of mac_labelmbufs, it's possible that a label will
+ * not be present, in which case NULL is returned. Policies must handle the
+ * possibility of an mbuf not having label storage if they do not enforce
+ * early loading.
+ */
+struct label *
+mac_mbuf_to_label(struct mbuf *m)
+{
+ struct m_tag *tag;
+ struct label *label;
+
+ if (m == NULL)
+ return (NULL);
+ tag = m_tag_find(m, PACKET_TAG_MACLABEL, NULL);
+ if (tag == NULL)
+ return (NULL);
+ label = (struct label *)(tag+1);
+ return (label);
+}
+
+static struct label *
+mac_bpfdesc_label_alloc(void)
+{
+ struct label *label;
+
+ label = mac_labelzone_alloc(M_WAITOK);
+ MAC_PERFORM(bpfdesc_init_label, label);
+ return (label);
+}
+
+void
+mac_bpfdesc_init(struct bpf_d *d)
+{
+
+ if (mac_labeled & MPC_OBJECT_BPFDESC)
+ d->bd_label = mac_bpfdesc_label_alloc();
+ else
+ d->bd_label = NULL;
+}
+
+static struct label *
+mac_ifnet_label_alloc(void)
+{
+ struct label *label;
+
+ label = mac_labelzone_alloc(M_WAITOK);
+ MAC_PERFORM(ifnet_init_label, label);
+ return (label);
+}
+
+void
+mac_ifnet_init(struct ifnet *ifp)
+{
+
+ if (mac_labeled & MPC_OBJECT_IFNET)
+ ifp->if_label = mac_ifnet_label_alloc();
+ else
+ ifp->if_label = NULL;
+}
+
+int
+mac_mbuf_tag_init(struct m_tag *tag, int flag)
+{
+ struct label *label;
+ int error;
+
+ label = (struct label *) (tag + 1);
+ mac_init_label(label);
+
+ MAC_CHECK(mbuf_init_label, label, flag);
+ if (error) {
+ MAC_PERFORM(mbuf_destroy_label, label);
+ mac_destroy_label(label);
+ }
+ return (error);
+}
+
+int
+mac_mbuf_init(struct mbuf *m, int flag)
+{
+ struct m_tag *tag;
+ int error;
+
+ M_ASSERTPKTHDR(m);
+
+ if (mac_labeled & MPC_OBJECT_MBUF) {
+ tag = m_tag_get(PACKET_TAG_MACLABEL, sizeof(struct label),
+ flag);
+ if (tag == NULL)
+ return (ENOMEM);
+ error = mac_mbuf_tag_init(tag, flag);
+ if (error) {
+ m_tag_free(tag);
+ return (error);
+ }
+ m_tag_prepend(m, tag);
+ }
+ return (0);
+}
+
+static void
+mac_bpfdesc_label_free(struct label *label)
+{
+
+ MAC_PERFORM(bpfdesc_destroy_label, label);
+ mac_labelzone_free(label);
+}
+
+void
+mac_bpfdesc_destroy(struct bpf_d *d)
+{
+
+ if (d->bd_label != NULL) {
+ mac_bpfdesc_label_free(d->bd_label);
+ d->bd_label = NULL;
+ }
+}
+
+static void
+mac_ifnet_label_free(struct label *label)
+{
+
+ MAC_PERFORM(ifnet_destroy_label, label);
+ mac_labelzone_free(label);
+}
+
+void
+mac_ifnet_destroy(struct ifnet *ifp)
+{
+
+ if (ifp->if_label != NULL) {
+ mac_ifnet_label_free(ifp->if_label);
+ ifp->if_label = NULL;
+ }
+}
+
+void
+mac_mbuf_tag_destroy(struct m_tag *tag)
+{
+ struct label *label;
+
+ label = (struct label *)(tag+1);
+
+ MAC_PERFORM(mbuf_destroy_label, label);
+ mac_destroy_label(label);
+}
+
+/*
+ * mac_mbuf_tag_copy is called when an mbuf header is duplicated, in which
+ * case the labels must also be duplicated.
+ */
+void
+mac_mbuf_tag_copy(struct m_tag *src, struct m_tag *dest)
+{
+ struct label *src_label, *dest_label;
+
+ src_label = (struct label *)(src+1);
+ dest_label = (struct label *)(dest+1);
+
+ /*
+ * mac_mbuf_tag_init() is called on the target tag in m_tag_copy(),
+ * so we don't need to call it here.
+ */
+ MAC_PERFORM(mbuf_copy_label, src_label, dest_label);
+}
+
+void
+mac_mbuf_copy(struct mbuf *m_from, struct mbuf *m_to)
+{
+ struct label *src_label, *dest_label;
+
+ src_label = mac_mbuf_to_label(m_from);
+ dest_label = mac_mbuf_to_label(m_to);
+
+ MAC_PERFORM(mbuf_copy_label, src_label, dest_label);
+}
+
+static void
+mac_ifnet_copy_label(struct label *src, struct label *dest)
+{
+
+ MAC_PERFORM(ifnet_copy_label, src, dest);
+}
+
+static int
+mac_ifnet_externalize_label(struct label *label, char *elements,
+ char *outbuf, size_t outbuflen)
+{
+ int error;
+
+ MAC_EXTERNALIZE(ifnet, label, elements, outbuf, outbuflen);
+
+ return (error);
+}
+
+static int
+mac_ifnet_internalize_label(struct label *label, char *string)
+{
+ int error;
+
+ MAC_INTERNALIZE(ifnet, label, string);
+
+ return (error);
+}
+
+void
+mac_ifnet_create(struct ifnet *ifp)
+{
+
+ MAC_IFNET_LOCK(ifp);
+ MAC_PERFORM(ifnet_create, ifp, ifp->if_label);
+ MAC_IFNET_UNLOCK(ifp);
+}
+
+void
+mac_bpfdesc_create(struct ucred *cred, struct bpf_d *d)
+{
+
+ MAC_PERFORM(bpfdesc_create, cred, d, d->bd_label);
+}
+
+void
+mac_bpfdesc_create_mbuf(struct bpf_d *d, struct mbuf *m)
+{
+ struct label *label;
+
+ BPFD_LOCK_ASSERT(d);
+
+ label = mac_mbuf_to_label(m);
+
+ MAC_PERFORM(bpfdesc_create_mbuf, d, d->bd_label, m, label);
+}
+
+void
+mac_ifnet_create_mbuf(struct ifnet *ifp, struct mbuf *m)
+{
+ struct label *label;
+
+ label = mac_mbuf_to_label(m);
+
+ MAC_IFNET_LOCK(ifp);
+ MAC_PERFORM(ifnet_create_mbuf, ifp, ifp->if_label, m, label);
+ MAC_IFNET_UNLOCK(ifp);
+}
+
+int
+mac_bpfdesc_check_receive(struct bpf_d *d, struct ifnet *ifp)
+{
+ int error;
+
+ BPFD_LOCK_ASSERT(d);
+
+ MAC_IFNET_LOCK(ifp);
+ MAC_CHECK(bpfdesc_check_receive, d, d->bd_label, ifp, ifp->if_label);
+ MAC_IFNET_UNLOCK(ifp);
+
+ return (error);
+}
+
+int
+mac_ifnet_check_transmit(struct ifnet *ifp, struct mbuf *m)
+{
+ struct label *label;
+ int error;
+
+ M_ASSERTPKTHDR(m);
+
+ label = mac_mbuf_to_label(m);
+
+ MAC_IFNET_LOCK(ifp);
+ MAC_CHECK(ifnet_check_transmit, ifp, ifp->if_label, m, label);
+ MAC_IFNET_UNLOCK(ifp);
+
+ return (error);
+}
+
+int
+mac_ifnet_ioctl_get(struct ucred *cred, struct ifreq *ifr,
+ struct ifnet *ifp)
+{
+ char *elements, *buffer;
+ struct label *intlabel;
+ struct mac mac;
+ int error;
+
+ if (!(mac_labeled & MPC_OBJECT_IFNET))
+ return (EINVAL);
+
+ error = copyin(ifr->ifr_ifru.ifru_data, &mac, sizeof(mac));
+ if (error)
+ return (error);
+
+ error = mac_check_structmac_consistent(&mac);
+ if (error)
+ return (error);
+
+ elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
+ error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
+ if (error) {
+ free(elements, M_MACTEMP);
+ return (error);
+ }
+
+ buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
+ intlabel = mac_ifnet_label_alloc();
+ MAC_IFNET_LOCK(ifp);
+ mac_ifnet_copy_label(ifp->if_label, intlabel);
+ MAC_IFNET_UNLOCK(ifp);
+ error = mac_ifnet_externalize_label(intlabel, elements, buffer,
+ mac.m_buflen);
+ mac_ifnet_label_free(intlabel);
+ if (error == 0)
+ error = copyout(buffer, mac.m_string, strlen(buffer)+1);
+
+ free(buffer, M_MACTEMP);
+ free(elements, M_MACTEMP);
+
+ return (error);
+}
+
+int
+mac_ifnet_ioctl_set(struct ucred *cred, struct ifreq *ifr, struct ifnet *ifp)
+{
+ struct label *intlabel;
+ struct mac mac;
+ char *buffer;
+ int error;
+
+ if (!(mac_labeled & MPC_OBJECT_IFNET))
+ return (EINVAL);
+
+ error = copyin(ifr->ifr_ifru.ifru_data, &mac, sizeof(mac));
+ if (error)
+ return (error);
+
+ error = mac_check_structmac_consistent(&mac);
+ if (error)
+ return (error);
+
+ buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
+ error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL);
+ if (error) {
+ free(buffer, M_MACTEMP);
+ return (error);
+ }
+
+ intlabel = mac_ifnet_label_alloc();
+ error = mac_ifnet_internalize_label(intlabel, buffer);
+ free(buffer, M_MACTEMP);
+ if (error) {
+ mac_ifnet_label_free(intlabel);
+ return (error);
+ }
+
+ /*
+ * XXX: Note that this is a redundant privilege check, since policies
+ * impose this check themselves if required by the policy
+ * Eventually, this should go away.
+ */
+ error = priv_check_cred(cred, PRIV_NET_SETIFMAC, 0);
+ if (error) {
+ mac_ifnet_label_free(intlabel);
+ return (error);
+ }
+
+ MAC_IFNET_LOCK(ifp);
+ MAC_CHECK(ifnet_check_relabel, cred, ifp, ifp->if_label, intlabel);
+ if (error) {
+ MAC_IFNET_UNLOCK(ifp);
+ mac_ifnet_label_free(intlabel);
+ return (error);
+ }
+
+ MAC_PERFORM(ifnet_relabel, cred, ifp, ifp->if_label, intlabel);
+ MAC_IFNET_UNLOCK(ifp);
+
+ mac_ifnet_label_free(intlabel);
+ return (0);
+}
diff --git a/sys/security/mac/mac_pipe.c b/sys/security/mac/mac_pipe.c
new file mode 100644
index 0000000..1d8ce04
--- /dev/null
+++ b/sys/security/mac/mac_pipe.c
@@ -0,0 +1,227 @@
+/*-
+ * Copyright (c) 2002-2003 Networks Associates Technology, Inc.
+ * Copyright (c) 2006 SPARTA, Inc.
+ * All rights reserved.
+ *
+ * This software was developed for the FreeBSD Project in part by Network
+ * Associates Laboratories, the Security Research Division of Network
+ * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"),
+ * as part of the DARPA CHATS research program.
+ *
+ * This software was enhanced by SPARTA ISSO under SPAWAR contract
+ * N66001-04-C-6019 ("SEFOS").
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "opt_mac.h"
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/sbuf.h>
+#include <sys/systm.h>
+#include <sys/vnode.h>
+#include <sys/pipe.h>
+#include <sys/sysctl.h>
+
+#include <security/mac/mac_framework.h>
+#include <security/mac/mac_internal.h>
+#include <security/mac/mac_policy.h>
+
+struct label *
+mac_pipe_label_alloc(void)
+{
+ struct label *label;
+
+ label = mac_labelzone_alloc(M_WAITOK);
+ MAC_PERFORM(pipe_init_label, label);
+ return (label);
+}
+
+void
+mac_pipe_init(struct pipepair *pp)
+{
+
+ if (mac_labeled & MPC_OBJECT_PIPE)
+ pp->pp_label = mac_pipe_label_alloc();
+ else
+ pp->pp_label = NULL;
+}
+
+void
+mac_pipe_label_free(struct label *label)
+{
+
+ MAC_PERFORM(pipe_destroy_label, label);
+ mac_labelzone_free(label);
+}
+
+void
+mac_pipe_destroy(struct pipepair *pp)
+{
+
+ if (pp->pp_label != NULL) {
+ mac_pipe_label_free(pp->pp_label);
+ pp->pp_label = NULL;
+ }
+}
+
+void
+mac_pipe_copy_label(struct label *src, struct label *dest)
+{
+
+ MAC_PERFORM(pipe_copy_label, src, dest);
+}
+
+int
+mac_pipe_externalize_label(struct label *label, char *elements,
+ char *outbuf, size_t outbuflen)
+{
+ int error;
+
+ MAC_EXTERNALIZE(pipe, label, elements, outbuf, outbuflen);
+
+ return (error);
+}
+
+int
+mac_pipe_internalize_label(struct label *label, char *string)
+{
+ int error;
+
+ MAC_INTERNALIZE(pipe, label, string);
+
+ return (error);
+}
+
+void
+mac_pipe_create(struct ucred *cred, struct pipepair *pp)
+{
+
+ MAC_PERFORM(pipe_create, cred, pp, pp->pp_label);
+}
+
+static void
+mac_pipe_relabel(struct ucred *cred, struct pipepair *pp,
+ struct label *newlabel)
+{
+
+ MAC_PERFORM(pipe_relabel, cred, pp, pp->pp_label, newlabel);
+}
+
+int
+mac_pipe_check_ioctl(struct ucred *cred, struct pipepair *pp,
+ unsigned long cmd, void *data)
+{
+ int error;
+
+ mtx_assert(&pp->pp_mtx, MA_OWNED);
+
+ MAC_CHECK(pipe_check_ioctl, cred, pp, pp->pp_label, cmd, data);
+
+ return (error);
+}
+
+int
+mac_pipe_check_poll(struct ucred *cred, struct pipepair *pp)
+{
+ int error;
+
+ mtx_assert(&pp->pp_mtx, MA_OWNED);
+
+ MAC_CHECK(pipe_check_poll, cred, pp, pp->pp_label);
+
+ return (error);
+}
+
+int
+mac_pipe_check_read(struct ucred *cred, struct pipepair *pp)
+{
+ int error;
+
+ mtx_assert(&pp->pp_mtx, MA_OWNED);
+
+ MAC_CHECK(pipe_check_read, cred, pp, pp->pp_label);
+
+ return (error);
+}
+
+static int
+mac_pipe_check_relabel(struct ucred *cred, struct pipepair *pp,
+ struct label *newlabel)
+{
+ int error;
+
+ mtx_assert(&pp->pp_mtx, MA_OWNED);
+
+ MAC_CHECK(pipe_check_relabel, cred, pp, pp->pp_label, newlabel);
+
+ return (error);
+}
+
+int
+mac_pipe_check_stat(struct ucred *cred, struct pipepair *pp)
+{
+ int error;
+
+ mtx_assert(&pp->pp_mtx, MA_OWNED);
+
+ MAC_CHECK(pipe_check_stat, cred, pp, pp->pp_label);
+
+ return (error);
+}
+
+int
+mac_pipe_check_write(struct ucred *cred, struct pipepair *pp)
+{
+ int error;
+
+ mtx_assert(&pp->pp_mtx, MA_OWNED);
+
+ MAC_CHECK(pipe_check_write, cred, pp, pp->pp_label);
+
+ return (error);
+}
+
+int
+mac_pipe_label_set(struct ucred *cred, struct pipepair *pp,
+ struct label *label)
+{
+ int error;
+
+ mtx_assert(&pp->pp_mtx, MA_OWNED);
+
+ error = mac_pipe_check_relabel(cred, pp, label);
+ if (error)
+ return (error);
+
+ mac_pipe_relabel(cred, pp, label);
+
+ return (0);
+}
diff --git a/sys/security/mac/mac_policy.h b/sys/security/mac/mac_policy.h
new file mode 100644
index 0000000..ecf68a6
--- /dev/null
+++ b/sys/security/mac/mac_policy.h
@@ -0,0 +1,1042 @@
+/*-
+ * Copyright (c) 1999-2002, 2007-2008 Robert N. M. Watson
+ * Copyright (c) 2001-2005 Networks Associates Technology, Inc.
+ * Copyright (c) 2005-2006 SPARTA, Inc.
+ * Copyright (c) 2008 Apple Inc.
+ * All rights reserved.
+ *
+ * This software was developed by Robert Watson for the TrustedBSD Project.
+ *
+ * This software was developed for the FreeBSD Project in part by Network
+ * Associates Laboratories, the Security Research Division of Network
+ * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"),
+ * as part of the DARPA CHATS research program.
+ *
+ * This software was enhanced by SPARTA ISSO under SPAWAR contract
+ * N66001-04-C-6019 ("SEFOS").
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+/*
+ * Kernel interface for MAC policy modules.
+ */
+#ifndef _SECURITY_MAC_MAC_POLICY_H_
+#define _SECURITY_MAC_MAC_POLICY_H_
+
+#ifndef _KERNEL
+#error "no user-serviceable parts inside"
+#endif
+
+/*-
+ * Pluggable access control policy definition structure.
+ *
+ * List of operations that are performed as part of the implementation of a
+ * MAC policy. Policy implementors declare operations with a mac_policy_ops
+ * structure, and using the MAC_POLICY_SET() macro. If an entry point is not
+ * declared, then then the policy will be ignored during evaluation of that
+ * event or check.
+ *
+ * Operations are sorted first by general class of operation, then
+ * alphabetically.
+ */
+#include <sys/acl.h> /* XXX acl_type_t */
+#include <sys/types.h> /* XXX accmode_t */
+
+struct acl;
+struct auditinfo;
+struct auditinfo_addr;
+struct bpf_d;
+struct cdev;
+struct componentname;
+struct devfs_dirent;
+struct ifnet;
+struct image_params;
+struct inpcb;
+struct ip6q;
+struct ipq;
+struct ksem;
+struct label;
+struct mac_policy_conf;
+struct mbuf;
+struct mount;
+struct msg;
+struct msqid_kernel;
+struct pipepair;
+struct proc;
+struct sbuf;
+struct semid_kernel;
+struct shmfd;
+struct shmid_kernel;
+struct sockaddr;
+struct socket;
+struct sysctl_oid;
+struct sysctl_req;
+struct thread;
+struct ucred;
+struct uio;
+struct vattr;
+struct vnode;
+
+/*
+ * Policy module operations.
+ */
+typedef void (*mpo_destroy_t)(struct mac_policy_conf *mpc);
+typedef void (*mpo_init_t)(struct mac_policy_conf *mpc);
+
+/*
+ * General policy-directed security system call so that policies may
+ * implement new services without reserving explicit system call numbers.
+ */
+typedef int (*mpo_syscall_t)(struct thread *td, int call, void *arg);
+
+/*
+ * Place-holder function pointers for ABI-compatibility purposes.
+ */
+typedef void (*mpo_placeholder_t)(void);
+
+/*
+ * Operations sorted alphabetically by primary object type and then method.
+ */
+typedef int (*mpo_bpfdesc_check_receive_t)(struct bpf_d *d,
+ struct label *dlabel, struct ifnet *ifp,
+ struct label *ifplabel);
+typedef void (*mpo_bpfdesc_create_t)(struct ucred *cred,
+ struct bpf_d *d, struct label *dlabel);
+typedef void (*mpo_bpfdesc_create_mbuf_t)(struct bpf_d *d,
+ struct label *dlabel, struct mbuf *m,
+ struct label *mlabel);
+typedef void (*mpo_bpfdesc_destroy_label_t)(struct label *label);
+typedef void (*mpo_bpfdesc_init_label_t)(struct label *label);
+
+typedef void (*mpo_cred_associate_nfsd_t)(struct ucred *cred);
+typedef int (*mpo_cred_check_relabel_t)(struct ucred *cred,
+ struct label *newlabel);
+typedef int (*mpo_cred_check_visible_t)(struct ucred *cr1,
+ struct ucred *cr2);
+typedef void (*mpo_cred_copy_label_t)(struct label *src,
+ struct label *dest);
+typedef void (*mpo_cred_create_init_t)(struct ucred *cred);
+typedef void (*mpo_cred_create_swapper_t)(struct ucred *cred);
+typedef void (*mpo_cred_destroy_label_t)(struct label *label);
+typedef int (*mpo_cred_externalize_label_t)(struct label *label,
+ char *element_name, struct sbuf *sb, int *claimed);
+typedef void (*mpo_cred_init_label_t)(struct label *label);
+typedef int (*mpo_cred_internalize_label_t)(struct label *label,
+ char *element_name, char *element_data, int *claimed);
+typedef void (*mpo_cred_relabel_t)(struct ucred *cred,
+ struct label *newlabel);
+
+typedef void (*mpo_devfs_create_device_t)(struct ucred *cred,
+ struct mount *mp, struct cdev *dev,
+ struct devfs_dirent *de, struct label *delabel);
+typedef void (*mpo_devfs_create_directory_t)(struct mount *mp,
+ char *dirname, int dirnamelen, struct devfs_dirent *de,
+ struct label *delabel);
+typedef void (*mpo_devfs_create_symlink_t)(struct ucred *cred,
+ struct mount *mp, struct devfs_dirent *dd,
+ struct label *ddlabel, struct devfs_dirent *de,
+ struct label *delabel);
+typedef void (*mpo_devfs_destroy_label_t)(struct label *label);
+typedef void (*mpo_devfs_init_label_t)(struct label *label);
+typedef void (*mpo_devfs_update_t)(struct mount *mp,
+ struct devfs_dirent *de, struct label *delabel,
+ struct vnode *vp, struct label *vplabel);
+typedef void (*mpo_devfs_vnode_associate_t)(struct mount *mp,
+ struct label *mplabel, struct devfs_dirent *de,
+ struct label *delabel, struct vnode *vp,
+ struct label *vplabel);
+
+typedef int (*mpo_ifnet_check_relabel_t)(struct ucred *cred,
+ struct ifnet *ifp, struct label *ifplabel,
+ struct label *newlabel);
+typedef int (*mpo_ifnet_check_transmit_t)(struct ifnet *ifp,
+ struct label *ifplabel, struct mbuf *m,
+ struct label *mlabel);
+typedef void (*mpo_ifnet_copy_label_t)(struct label *src,
+ struct label *dest);
+typedef void (*mpo_ifnet_create_t)(struct ifnet *ifp,
+ struct label *ifplabel);
+typedef void (*mpo_ifnet_create_mbuf_t)(struct ifnet *ifp,
+ struct label *ifplabel, struct mbuf *m,
+ struct label *mlabel);
+typedef void (*mpo_ifnet_destroy_label_t)(struct label *label);
+typedef int (*mpo_ifnet_externalize_label_t)(struct label *label,
+ char *element_name, struct sbuf *sb, int *claimed);
+typedef void (*mpo_ifnet_init_label_t)(struct label *label);
+typedef int (*mpo_ifnet_internalize_label_t)(struct label *label,
+ char *element_name, char *element_data, int *claimed);
+typedef void (*mpo_ifnet_relabel_t)(struct ucred *cred, struct ifnet *ifp,
+ struct label *ifplabel, struct label *newlabel);
+
+typedef int (*mpo_inpcb_check_deliver_t)(struct inpcb *inp,
+ struct label *inplabel, struct mbuf *m,
+ struct label *mlabel);
+typedef int (*mpo_inpcb_check_visible_t)(struct ucred *cred,
+ struct inpcb *inp, struct label *inplabel);
+typedef void (*mpo_inpcb_create_t)(struct socket *so,
+ struct label *solabel, struct inpcb *inp,
+ struct label *inplabel);
+typedef void (*mpo_inpcb_create_mbuf_t)(struct inpcb *inp,
+ struct label *inplabel, struct mbuf *m,
+ struct label *mlabel);
+typedef void (*mpo_inpcb_destroy_label_t)(struct label *label);
+typedef int (*mpo_inpcb_init_label_t)(struct label *label, int flag);
+typedef void (*mpo_inpcb_sosetlabel_t)(struct socket *so,
+ struct label *label, struct inpcb *inp,
+ struct label *inplabel);
+
+typedef void (*mpo_ip6q_create_t)(struct mbuf *m, struct label *mlabel,
+ struct ip6q *q6, struct label *q6label);
+typedef void (*mpo_ip6q_destroy_label_t)(struct label *label);
+typedef int (*mpo_ip6q_init_label_t)(struct label *label, int flag);
+typedef int (*mpo_ip6q_match_t)(struct mbuf *m, struct label *mlabel,
+ struct ip6q *q6, struct label *q6label);
+typedef void (*mpo_ip6q_reassemble)(struct ip6q *q6, struct label *q6label,
+ struct mbuf *m, struct label *mlabel);
+typedef void (*mpo_ip6q_update_t)(struct mbuf *m, struct label *mlabel,
+ struct ip6q *q6, struct label *q6label);
+
+typedef void (*mpo_ipq_create_t)(struct mbuf *m, struct label *mlabel,
+ struct ipq *q, struct label *qlabel);
+typedef void (*mpo_ipq_destroy_label_t)(struct label *label);
+typedef int (*mpo_ipq_init_label_t)(struct label *label, int flag);
+typedef int (*mpo_ipq_match_t)(struct mbuf *m, struct label *mlabel,
+ struct ipq *q, struct label *qlabel);
+typedef void (*mpo_ipq_reassemble)(struct ipq *q, struct label *qlabel,
+ struct mbuf *m, struct label *mlabel);
+typedef void (*mpo_ipq_update_t)(struct mbuf *m, struct label *mlabel,
+ struct ipq *q, struct label *qlabel);
+
+typedef int (*mpo_kenv_check_dump_t)(struct ucred *cred);
+typedef int (*mpo_kenv_check_get_t)(struct ucred *cred, char *name);
+typedef int (*mpo_kenv_check_set_t)(struct ucred *cred, char *name,
+ char *value);
+typedef int (*mpo_kenv_check_unset_t)(struct ucred *cred, char *name);
+
+typedef int (*mpo_kld_check_load_t)(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel);
+typedef int (*mpo_kld_check_stat_t)(struct ucred *cred);
+
+typedef void (*mpo_mbuf_copy_label_t)(struct label *src,
+ struct label *dest);
+typedef void (*mpo_mbuf_destroy_label_t)(struct label *label);
+typedef int (*mpo_mbuf_init_label_t)(struct label *label, int flag);
+
+typedef int (*mpo_mount_check_stat_t)(struct ucred *cred,
+ struct mount *mp, struct label *mplabel);
+typedef void (*mpo_mount_create_t)(struct ucred *cred, struct mount *mp,
+ struct label *mplabel);
+typedef void (*mpo_mount_destroy_label_t)(struct label *label);
+typedef void (*mpo_mount_init_label_t)(struct label *label);
+
+typedef void (*mpo_netatalk_aarp_send_t)(struct ifnet *ifp,
+ struct label *ifplabel, struct mbuf *m,
+ struct label *mlabel);
+
+typedef void (*mpo_netinet_arp_send_t)(struct ifnet *ifp,
+ struct label *ifplabel, struct mbuf *m,
+ struct label *mlabel);
+typedef void (*mpo_netinet_firewall_reply_t)(struct mbuf *mrecv,
+ struct label *mrecvlabel, struct mbuf *msend,
+ struct label *msendlabel);
+typedef void (*mpo_netinet_firewall_send_t)(struct mbuf *m,
+ struct label *mlabel);
+typedef void (*mpo_netinet_fragment_t)(struct mbuf *m,
+ struct label *mlabel, struct mbuf *frag,
+ struct label *fraglabel);
+typedef void (*mpo_netinet_icmp_reply_t)(struct mbuf *mrecv,
+ struct label *mrecvlabel, struct mbuf *msend,
+ struct label *msendlabel);
+typedef void (*mpo_netinet_icmp_replyinplace_t)(struct mbuf *m,
+ struct label *mlabel);
+typedef void (*mpo_netinet_igmp_send_t)(struct ifnet *ifp,
+ struct label *ifplabel, struct mbuf *m,
+ struct label *mlabel);
+typedef void (*mpo_netinet_tcp_reply_t)(struct mbuf *m,
+ struct label *mlabel);
+
+typedef void (*mpo_netinet6_nd6_send_t)(struct ifnet *ifp,
+ struct label *ifplabel, struct mbuf *m,
+ struct label *mlabel);
+
+typedef int (*mpo_pipe_check_ioctl_t)(struct ucred *cred,
+ struct pipepair *pp, struct label *pplabel,
+ unsigned long cmd, void *data);
+typedef int (*mpo_pipe_check_poll_t)(struct ucred *cred,
+ struct pipepair *pp, struct label *pplabel);
+typedef int (*mpo_pipe_check_read_t)(struct ucred *cred,
+ struct pipepair *pp, struct label *pplabel);
+typedef int (*mpo_pipe_check_relabel_t)(struct ucred *cred,
+ struct pipepair *pp, struct label *pplabel,
+ struct label *newlabel);
+typedef int (*mpo_pipe_check_stat_t)(struct ucred *cred,
+ struct pipepair *pp, struct label *pplabel);
+typedef int (*mpo_pipe_check_write_t)(struct ucred *cred,
+ struct pipepair *pp, struct label *pplabel);
+typedef void (*mpo_pipe_copy_label_t)(struct label *src,
+ struct label *dest);
+typedef void (*mpo_pipe_create_t)(struct ucred *cred, struct pipepair *pp,
+ struct label *pplabel);
+typedef void (*mpo_pipe_destroy_label_t)(struct label *label);
+typedef int (*mpo_pipe_externalize_label_t)(struct label *label,
+ char *element_name, struct sbuf *sb, int *claimed);
+typedef void (*mpo_pipe_init_label_t)(struct label *label);
+typedef int (*mpo_pipe_internalize_label_t)(struct label *label,
+ char *element_name, char *element_data, int *claimed);
+typedef void (*mpo_pipe_relabel_t)(struct ucred *cred, struct pipepair *pp,
+ struct label *oldlabel, struct label *newlabel);
+
+typedef int (*mpo_posixsem_check_getvalue_t)(struct ucred *active_cred,
+ struct ucred *file_cred, struct ksem *ks,
+ struct label *kslabel);
+typedef int (*mpo_posixsem_check_open_t)(struct ucred *cred,
+ struct ksem *ks, struct label *kslabel);
+typedef int (*mpo_posixsem_check_post_t)(struct ucred *active_cred,
+ struct ucred *file_cred, struct ksem *ks,
+ struct label *kslabel);
+typedef int (*mpo_posixsem_check_stat_t)(struct ucred *active_cred,
+ struct ucred *file_cred, struct ksem *ks,
+ struct label *kslabel);
+typedef int (*mpo_posixsem_check_unlink_t)(struct ucred *cred,
+ struct ksem *ks, struct label *kslabel);
+typedef int (*mpo_posixsem_check_wait_t)(struct ucred *active_cred,
+ struct ucred *file_cred, struct ksem *ks,
+ struct label *kslabel);
+typedef void (*mpo_posixsem_create_t)(struct ucred *cred,
+ struct ksem *ks, struct label *kslabel);
+typedef void (*mpo_posixsem_destroy_label_t)(struct label *label);
+typedef void (*mpo_posixsem_init_label_t)(struct label *label);
+
+typedef int (*mpo_posixshm_check_mmap_t)(struct ucred *cred,
+ struct shmfd *shmfd, struct label *shmlabel, int prot,
+ int flags);
+typedef int (*mpo_posixshm_check_open_t)(struct ucred *cred,
+ struct shmfd *shmfd, struct label *shmlabel);
+typedef int (*mpo_posixshm_check_stat_t)(struct ucred *active_cred,
+ struct ucred *file_cred, struct shmfd *shmfd,
+ struct label *shmlabel);
+typedef int (*mpo_posixshm_check_truncate_t)(struct ucred *active_cred,
+ struct ucred *file_cred, struct shmfd *shmfd,
+ struct label *shmlabel);
+typedef int (*mpo_posixshm_check_unlink_t)(struct ucred *cred,
+ struct shmfd *shmfd, struct label *shmlabel);
+typedef void (*mpo_posixshm_create_t)(struct ucred *cred,
+ struct shmfd *shmfd, struct label *shmlabel);
+typedef void (*mpo_posixshm_destroy_label_t)(struct label *label);
+typedef void (*mpo_posixshm_init_label_t)(struct label *label);
+
+typedef int (*mpo_priv_check_t)(struct ucred *cred, int priv);
+typedef int (*mpo_priv_grant_t)(struct ucred *cred, int priv);
+
+typedef int (*mpo_proc_check_debug_t)(struct ucred *cred,
+ struct proc *p);
+typedef int (*mpo_proc_check_sched_t)(struct ucred *cred,
+ struct proc *p);
+typedef int (*mpo_proc_check_setaudit_t)(struct ucred *cred,
+ struct auditinfo *ai);
+typedef int (*mpo_proc_check_setaudit_addr_t)(struct ucred *cred,
+ struct auditinfo_addr *aia);
+typedef int (*mpo_proc_check_setauid_t)(struct ucred *cred, uid_t auid);
+typedef int (*mpo_proc_check_setegid_t)(struct ucred *cred, gid_t egid);
+typedef int (*mpo_proc_check_seteuid_t)(struct ucred *cred, uid_t euid);
+typedef int (*mpo_proc_check_setgid_t)(struct ucred *cred, gid_t gid);
+typedef int (*mpo_proc_check_setgroups_t)(struct ucred *cred, int ngroups,
+ gid_t *gidset);
+typedef int (*mpo_proc_check_setregid_t)(struct ucred *cred, gid_t rgid,
+ gid_t egid);
+typedef int (*mpo_proc_check_setresgid_t)(struct ucred *cred, gid_t rgid,
+ gid_t egid, gid_t sgid);
+typedef int (*mpo_proc_check_setresuid_t)(struct ucred *cred, uid_t ruid,
+ uid_t euid, uid_t suid);
+typedef int (*mpo_proc_check_setreuid_t)(struct ucred *cred, uid_t ruid,
+ uid_t euid);
+typedef int (*mpo_proc_check_setuid_t)(struct ucred *cred, uid_t uid);
+typedef int (*mpo_proc_check_signal_t)(struct ucred *cred,
+ struct proc *proc, int signum);
+typedef int (*mpo_proc_check_wait_t)(struct ucred *cred,
+ struct proc *proc);
+typedef void (*mpo_proc_destroy_label_t)(struct label *label);
+typedef void (*mpo_proc_init_label_t)(struct label *label);
+
+typedef int (*mpo_socket_check_accept_t)(struct ucred *cred,
+ struct socket *so, struct label *solabel);
+typedef int (*mpo_socket_check_bind_t)(struct ucred *cred,
+ struct socket *so, struct label *solabel,
+ struct sockaddr *sa);
+typedef int (*mpo_socket_check_connect_t)(struct ucred *cred,
+ struct socket *so, struct label *solabel,
+ struct sockaddr *sa);
+typedef int (*mpo_socket_check_create_t)(struct ucred *cred, int domain,
+ int type, int protocol);
+typedef int (*mpo_socket_check_deliver_t)(struct socket *so,
+ struct label *solabel, struct mbuf *m,
+ struct label *mlabel);
+typedef int (*mpo_socket_check_listen_t)(struct ucred *cred,
+ struct socket *so, struct label *solabel);
+typedef int (*mpo_socket_check_poll_t)(struct ucred *cred,
+ struct socket *so, struct label *solabel);
+typedef int (*mpo_socket_check_receive_t)(struct ucred *cred,
+ struct socket *so, struct label *solabel);
+typedef int (*mpo_socket_check_relabel_t)(struct ucred *cred,
+ struct socket *so, struct label *solabel,
+ struct label *newlabel);
+typedef int (*mpo_socket_check_send_t)(struct ucred *cred,
+ struct socket *so, struct label *solabel);
+typedef int (*mpo_socket_check_stat_t)(struct ucred *cred,
+ struct socket *so, struct label *solabel);
+typedef int (*mpo_socket_check_visible_t)(struct ucred *cred,
+ struct socket *so, struct label *solabel);
+typedef void (*mpo_socket_copy_label_t)(struct label *src,
+ struct label *dest);
+typedef void (*mpo_socket_create_t)(struct ucred *cred, struct socket *so,
+ struct label *solabel);
+typedef void (*mpo_socket_create_mbuf_t)(struct socket *so,
+ struct label *solabel, struct mbuf *m,
+ struct label *mlabel);
+typedef void (*mpo_socket_destroy_label_t)(struct label *label);
+typedef int (*mpo_socket_externalize_label_t)(struct label *label,
+ char *element_name, struct sbuf *sb, int *claimed);
+typedef int (*mpo_socket_init_label_t)(struct label *label, int flag);
+typedef int (*mpo_socket_internalize_label_t)(struct label *label,
+ char *element_name, char *element_data, int *claimed);
+typedef void (*mpo_socket_newconn_t)(struct socket *oldso,
+ struct label *oldsolabel, struct socket *newso,
+ struct label *newsolabel);
+typedef void (*mpo_socket_relabel_t)(struct ucred *cred, struct socket *so,
+ struct label *oldlabel, struct label *newlabel);
+
+typedef void (*mpo_socketpeer_destroy_label_t)(struct label *label);
+typedef int (*mpo_socketpeer_externalize_label_t)(struct label *label,
+ char *element_name, struct sbuf *sb, int *claimed);
+typedef int (*mpo_socketpeer_init_label_t)(struct label *label,
+ int flag);
+typedef void (*mpo_socketpeer_set_from_mbuf_t)(struct mbuf *m,
+ struct label *mlabel, struct socket *so,
+ struct label *sopeerlabel);
+typedef void (*mpo_socketpeer_set_from_socket_t)(struct socket *oldso,
+ struct label *oldsolabel, struct socket *newso,
+ struct label *newsopeerlabel);
+
+typedef void (*mpo_syncache_create_t)(struct label *label,
+ struct inpcb *inp);
+typedef void (*mpo_syncache_create_mbuf_t)(struct label *sc_label,
+ struct mbuf *m, struct label *mlabel);
+typedef void (*mpo_syncache_destroy_label_t)(struct label *label);
+typedef int (*mpo_syncache_init_label_t)(struct label *label, int flag);
+
+typedef int (*mpo_system_check_acct_t)(struct ucred *cred,
+ struct vnode *vp, struct label *vplabel);
+typedef int (*mpo_system_check_audit_t)(struct ucred *cred, void *record,
+ int length);
+typedef int (*mpo_system_check_auditctl_t)(struct ucred *cred,
+ struct vnode *vp, struct label *vplabel);
+typedef int (*mpo_system_check_auditon_t)(struct ucred *cred, int cmd);
+typedef int (*mpo_system_check_reboot_t)(struct ucred *cred, int howto);
+typedef int (*mpo_system_check_swapon_t)(struct ucred *cred,
+ struct vnode *vp, struct label *vplabel);
+typedef int (*mpo_system_check_swapoff_t)(struct ucred *cred,
+ struct vnode *vp, struct label *vplabel);
+typedef int (*mpo_system_check_sysctl_t)(struct ucred *cred,
+ struct sysctl_oid *oidp, void *arg1, int arg2,
+ struct sysctl_req *req);
+
+typedef void (*mpo_sysvmsg_cleanup_t)(struct label *msglabel);
+typedef void (*mpo_sysvmsg_create_t)(struct ucred *cred,
+ struct msqid_kernel *msqkptr, struct label *msqlabel,
+ struct msg *msgptr, struct label *msglabel);
+typedef void (*mpo_sysvmsg_destroy_label_t)(struct label *label);
+typedef void (*mpo_sysvmsg_init_label_t)(struct label *label);
+
+typedef int (*mpo_sysvmsq_check_msgmsq_t)(struct ucred *cred,
+ struct msg *msgptr, struct label *msglabel,
+ struct msqid_kernel *msqkptr, struct label *msqklabel);
+typedef int (*mpo_sysvmsq_check_msgrcv_t)(struct ucred *cred,
+ struct msg *msgptr, struct label *msglabel);
+typedef int (*mpo_sysvmsq_check_msgrmid_t)(struct ucred *cred,
+ struct msg *msgptr, struct label *msglabel);
+typedef int (*mpo_sysvmsq_check_msqget_t)(struct ucred *cred,
+ struct msqid_kernel *msqkptr, struct label *msqklabel);
+typedef int (*mpo_sysvmsq_check_msqctl_t)(struct ucred *cred,
+ struct msqid_kernel *msqkptr, struct label *msqklabel,
+ int cmd);
+typedef int (*mpo_sysvmsq_check_msqrcv_t)(struct ucred *cred,
+ struct msqid_kernel *msqkptr, struct label *msqklabel);
+typedef int (*mpo_sysvmsq_check_msqsnd_t)(struct ucred *cred,
+ struct msqid_kernel *msqkptr, struct label *msqklabel);
+typedef void (*mpo_sysvmsq_cleanup_t)(struct label *msqlabel);
+typedef void (*mpo_sysvmsq_create_t)(struct ucred *cred,
+ struct msqid_kernel *msqkptr, struct label *msqlabel);
+typedef void (*mpo_sysvmsq_destroy_label_t)(struct label *label);
+typedef void (*mpo_sysvmsq_init_label_t)(struct label *label);
+
+typedef int (*mpo_sysvsem_check_semctl_t)(struct ucred *cred,
+ struct semid_kernel *semakptr, struct label *semaklabel,
+ int cmd);
+typedef int (*mpo_sysvsem_check_semget_t)(struct ucred *cred,
+ struct semid_kernel *semakptr, struct label *semaklabel);
+typedef int (*mpo_sysvsem_check_semop_t)(struct ucred *cred,
+ struct semid_kernel *semakptr, struct label *semaklabel,
+ size_t accesstype);
+typedef void (*mpo_sysvsem_cleanup_t)(struct label *semalabel);
+typedef void (*mpo_sysvsem_create_t)(struct ucred *cred,
+ struct semid_kernel *semakptr, struct label *semalabel);
+typedef void (*mpo_sysvsem_destroy_label_t)(struct label *label);
+typedef void (*mpo_sysvsem_init_label_t)(struct label *label);
+
+typedef int (*mpo_sysvshm_check_shmat_t)(struct ucred *cred,
+ struct shmid_kernel *shmsegptr,
+ struct label *shmseglabel, int shmflg);
+typedef int (*mpo_sysvshm_check_shmctl_t)(struct ucred *cred,
+ struct shmid_kernel *shmsegptr,
+ struct label *shmseglabel, int cmd);
+typedef int (*mpo_sysvshm_check_shmdt_t)(struct ucred *cred,
+ struct shmid_kernel *shmsegptr,
+ struct label *shmseglabel);
+typedef int (*mpo_sysvshm_check_shmget_t)(struct ucred *cred,
+ struct shmid_kernel *shmsegptr,
+ struct label *shmseglabel, int shmflg);
+typedef void (*mpo_sysvshm_cleanup_t)(struct label *shmlabel);
+typedef void (*mpo_sysvshm_create_t)(struct ucred *cred,
+ struct shmid_kernel *shmsegptr, struct label *shmlabel);
+typedef void (*mpo_sysvshm_destroy_label_t)(struct label *label);
+typedef void (*mpo_sysvshm_init_label_t)(struct label *label);
+
+typedef void (*mpo_thread_userret_t)(struct thread *thread);
+
+typedef int (*mpo_vnode_associate_extattr_t)(struct mount *mp,
+ struct label *mplabel, struct vnode *vp,
+ struct label *vplabel);
+typedef void (*mpo_vnode_associate_singlelabel_t)(struct mount *mp,
+ struct label *mplabel, struct vnode *vp,
+ struct label *vplabel);
+typedef int (*mpo_vnode_check_access_t)(struct ucred *cred,
+ struct vnode *vp, struct label *vplabel,
+ accmode_t accmode);
+typedef int (*mpo_vnode_check_chdir_t)(struct ucred *cred,
+ struct vnode *dvp, struct label *dvplabel);
+typedef int (*mpo_vnode_check_chroot_t)(struct ucred *cred,
+ struct vnode *dvp, struct label *dvplabel);
+typedef int (*mpo_vnode_check_create_t)(struct ucred *cred,
+ struct vnode *dvp, struct label *dvplabel,
+ struct componentname *cnp, struct vattr *vap);
+typedef int (*mpo_vnode_check_deleteacl_t)(struct ucred *cred,
+ struct vnode *vp, struct label *vplabel,
+ acl_type_t type);
+typedef int (*mpo_vnode_check_deleteextattr_t)(struct ucred *cred,
+ struct vnode *vp, struct label *vplabel,
+ int attrnamespace, const char *name);
+typedef int (*mpo_vnode_check_exec_t)(struct ucred *cred,
+ struct vnode *vp, struct label *vplabel,
+ struct image_params *imgp, struct label *execlabel);
+typedef int (*mpo_vnode_check_getacl_t)(struct ucred *cred,
+ struct vnode *vp, struct label *vplabel,
+ acl_type_t type);
+typedef int (*mpo_vnode_check_getextattr_t)(struct ucred *cred,
+ struct vnode *vp, struct label *vplabel,
+ int attrnamespace, const char *name, struct uio *uio);
+typedef int (*mpo_vnode_check_link_t)(struct ucred *cred,
+ struct vnode *dvp, struct label *dvplabel,
+ struct vnode *vp, struct label *vplabel,
+ struct componentname *cnp);
+typedef int (*mpo_vnode_check_listextattr_t)(struct ucred *cred,
+ struct vnode *vp, struct label *vplabel,
+ int attrnamespace);
+typedef int (*mpo_vnode_check_lookup_t)(struct ucred *cred,
+ struct vnode *dvp, struct label *dvplabel,
+ struct componentname *cnp);
+typedef int (*mpo_vnode_check_mmap_t)(struct ucred *cred,
+ struct vnode *vp, struct label *label, int prot,
+ int flags);
+typedef void (*mpo_vnode_check_mmap_downgrade_t)(struct ucred *cred,
+ struct vnode *vp, struct label *vplabel, int *prot);
+typedef int (*mpo_vnode_check_mprotect_t)(struct ucred *cred,
+ struct vnode *vp, struct label *vplabel, int prot);
+typedef int (*mpo_vnode_check_open_t)(struct ucred *cred,
+ struct vnode *vp, struct label *vplabel,
+ accmode_t accmode);
+typedef int (*mpo_vnode_check_poll_t)(struct ucred *active_cred,
+ struct ucred *file_cred, struct vnode *vp,
+ struct label *vplabel);
+typedef int (*mpo_vnode_check_read_t)(struct ucred *active_cred,
+ struct ucred *file_cred, struct vnode *vp,
+ struct label *vplabel);
+typedef int (*mpo_vnode_check_readdir_t)(struct ucred *cred,
+ struct vnode *dvp, struct label *dvplabel);
+typedef int (*mpo_vnode_check_readlink_t)(struct ucred *cred,
+ struct vnode *vp, struct label *vplabel);
+typedef int (*mpo_vnode_check_relabel_t)(struct ucred *cred,
+ struct vnode *vp, struct label *vplabel,
+ struct label *newlabel);
+typedef int (*mpo_vnode_check_rename_from_t)(struct ucred *cred,
+ struct vnode *dvp, struct label *dvplabel,
+ struct vnode *vp, struct label *vplabel,
+ struct componentname *cnp);
+typedef int (*mpo_vnode_check_rename_to_t)(struct ucred *cred,
+ struct vnode *dvp, struct label *dvplabel,
+ struct vnode *vp, struct label *vplabel, int samedir,
+ struct componentname *cnp);
+typedef int (*mpo_vnode_check_revoke_t)(struct ucred *cred,
+ struct vnode *vp, struct label *vplabel);
+typedef int (*mpo_vnode_check_setacl_t)(struct ucred *cred,
+ struct vnode *vp, struct label *vplabel, acl_type_t type,
+ struct acl *acl);
+typedef int (*mpo_vnode_check_setextattr_t)(struct ucred *cred,
+ struct vnode *vp, struct label *vplabel,
+ int attrnamespace, const char *name, struct uio *uio);
+typedef int (*mpo_vnode_check_setflags_t)(struct ucred *cred,
+ struct vnode *vp, struct label *vplabel, u_long flags);
+typedef int (*mpo_vnode_check_setmode_t)(struct ucred *cred,
+ struct vnode *vp, struct label *vplabel, mode_t mode);
+typedef int (*mpo_vnode_check_setowner_t)(struct ucred *cred,
+ struct vnode *vp, struct label *vplabel, uid_t uid,
+ gid_t gid);
+typedef int (*mpo_vnode_check_setutimes_t)(struct ucred *cred,
+ struct vnode *vp, struct label *vplabel,
+ struct timespec atime, struct timespec mtime);
+typedef int (*mpo_vnode_check_stat_t)(struct ucred *active_cred,
+ struct ucred *file_cred, struct vnode *vp,
+ struct label *vplabel);
+typedef int (*mpo_vnode_check_unlink_t)(struct ucred *cred,
+ struct vnode *dvp, struct label *dvplabel,
+ struct vnode *vp, struct label *vplabel,
+ struct componentname *cnp);
+typedef int (*mpo_vnode_check_write_t)(struct ucred *active_cred,
+ struct ucred *file_cred, struct vnode *vp,
+ struct label *vplabel);
+typedef void (*mpo_vnode_copy_label_t)(struct label *src,
+ struct label *dest);
+typedef int (*mpo_vnode_create_extattr_t)(struct ucred *cred,
+ struct mount *mp, struct label *mplabel,
+ struct vnode *dvp, struct label *dvplabel,
+ struct vnode *vp, struct label *vplabel,
+ struct componentname *cnp);
+typedef void (*mpo_vnode_destroy_label_t)(struct label *label);
+typedef void (*mpo_vnode_execve_transition_t)(struct ucred *old,
+ struct ucred *new, struct vnode *vp,
+ struct label *vplabel, struct label *interpvplabel,
+ struct image_params *imgp, struct label *execlabel);
+typedef int (*mpo_vnode_execve_will_transition_t)(struct ucred *old,
+ struct vnode *vp, struct label *vplabel,
+ struct label *interpvplabel, struct image_params *imgp,
+ struct label *execlabel);
+typedef int (*mpo_vnode_externalize_label_t)(struct label *label,
+ char *element_name, struct sbuf *sb, int *claimed);
+typedef void (*mpo_vnode_init_label_t)(struct label *label);
+typedef int (*mpo_vnode_internalize_label_t)(struct label *label,
+ char *element_name, char *element_data, int *claimed);
+typedef void (*mpo_vnode_relabel_t)(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, struct label *label);
+typedef int (*mpo_vnode_setlabel_extattr_t)(struct ucred *cred,
+ struct vnode *vp, struct label *vplabel,
+ struct label *intlabel);
+
+struct mac_policy_ops {
+ /*
+ * Policy module operations.
+ */
+ mpo_destroy_t mpo_destroy;
+ mpo_init_t mpo_init;
+
+ /*
+ * General policy-directed security system call so that policies may
+ * implement new services without reserving explicit system call
+ * numbers.
+ */
+ mpo_syscall_t mpo_syscall;
+
+ /*
+ * Label operations. Initialize label storage, destroy label
+ * storage, recycle for re-use without init/destroy, copy a label to
+ * initialized storage, and externalize/internalize from/to
+ * initialized storage.
+ */
+ mpo_bpfdesc_check_receive_t mpo_bpfdesc_check_receive;
+ mpo_bpfdesc_create_t mpo_bpfdesc_create;
+ mpo_bpfdesc_create_mbuf_t mpo_bpfdesc_create_mbuf;
+ mpo_bpfdesc_destroy_label_t mpo_bpfdesc_destroy_label;
+ mpo_bpfdesc_init_label_t mpo_bpfdesc_init_label;
+
+ mpo_cred_associate_nfsd_t mpo_cred_associate_nfsd;
+ mpo_cred_check_relabel_t mpo_cred_check_relabel;
+ mpo_cred_check_visible_t mpo_cred_check_visible;
+ mpo_cred_copy_label_t mpo_cred_copy_label;
+ mpo_cred_create_swapper_t mpo_cred_create_swapper;
+ mpo_cred_create_init_t mpo_cred_create_init;
+ mpo_cred_destroy_label_t mpo_cred_destroy_label;
+ mpo_cred_externalize_label_t mpo_cred_externalize_label;
+ mpo_cred_init_label_t mpo_cred_init_label;
+ mpo_cred_internalize_label_t mpo_cred_internalize_label;
+ mpo_cred_relabel_t mpo_cred_relabel;
+
+ mpo_devfs_create_device_t mpo_devfs_create_device;
+ mpo_devfs_create_directory_t mpo_devfs_create_directory;
+ mpo_devfs_create_symlink_t mpo_devfs_create_symlink;
+ mpo_devfs_destroy_label_t mpo_devfs_destroy_label;
+ mpo_devfs_init_label_t mpo_devfs_init_label;
+ mpo_devfs_update_t mpo_devfs_update;
+ mpo_devfs_vnode_associate_t mpo_devfs_vnode_associate;
+
+ mpo_ifnet_check_relabel_t mpo_ifnet_check_relabel;
+ mpo_ifnet_check_transmit_t mpo_ifnet_check_transmit;
+ mpo_ifnet_copy_label_t mpo_ifnet_copy_label;
+ mpo_ifnet_create_t mpo_ifnet_create;
+ mpo_ifnet_create_mbuf_t mpo_ifnet_create_mbuf;
+ mpo_ifnet_destroy_label_t mpo_ifnet_destroy_label;
+ mpo_ifnet_externalize_label_t mpo_ifnet_externalize_label;
+ mpo_ifnet_init_label_t mpo_ifnet_init_label;
+ mpo_ifnet_internalize_label_t mpo_ifnet_internalize_label;
+ mpo_ifnet_relabel_t mpo_ifnet_relabel;
+
+ mpo_inpcb_check_deliver_t mpo_inpcb_check_deliver;
+ mpo_inpcb_check_visible_t mpo_inpcb_check_visible;
+ mpo_inpcb_create_t mpo_inpcb_create;
+ mpo_inpcb_create_mbuf_t mpo_inpcb_create_mbuf;
+ mpo_inpcb_destroy_label_t mpo_inpcb_destroy_label;
+ mpo_inpcb_init_label_t mpo_inpcb_init_label;
+ mpo_inpcb_sosetlabel_t mpo_inpcb_sosetlabel;
+
+ mpo_ip6q_create_t mpo_ip6q_create;
+ mpo_ip6q_destroy_label_t mpo_ip6q_destroy_label;
+ mpo_ip6q_init_label_t mpo_ip6q_init_label;
+ mpo_ip6q_match_t mpo_ip6q_match;
+ mpo_ip6q_reassemble mpo_ip6q_reassemble;
+ mpo_ip6q_update_t mpo_ip6q_update;
+
+ mpo_ipq_create_t mpo_ipq_create;
+ mpo_ipq_destroy_label_t mpo_ipq_destroy_label;
+ mpo_ipq_init_label_t mpo_ipq_init_label;
+ mpo_ipq_match_t mpo_ipq_match;
+ mpo_ipq_reassemble mpo_ipq_reassemble;
+ mpo_ipq_update_t mpo_ipq_update;
+
+ mpo_kenv_check_dump_t mpo_kenv_check_dump;
+ mpo_kenv_check_get_t mpo_kenv_check_get;
+ mpo_kenv_check_set_t mpo_kenv_check_set;
+ mpo_kenv_check_unset_t mpo_kenv_check_unset;
+
+ mpo_kld_check_load_t mpo_kld_check_load;
+ mpo_kld_check_stat_t mpo_kld_check_stat;
+
+ mpo_mbuf_copy_label_t mpo_mbuf_copy_label;
+ mpo_mbuf_destroy_label_t mpo_mbuf_destroy_label;
+ mpo_mbuf_init_label_t mpo_mbuf_init_label;
+
+ mpo_mount_check_stat_t mpo_mount_check_stat;
+ mpo_mount_create_t mpo_mount_create;
+ mpo_mount_destroy_label_t mpo_mount_destroy_label;
+ mpo_mount_init_label_t mpo_mount_init_label;
+
+ mpo_netatalk_aarp_send_t mpo_netatalk_aarp_send;
+
+ mpo_netinet_arp_send_t mpo_netinet_arp_send;
+ mpo_netinet_firewall_reply_t mpo_netinet_firewall_reply;
+ mpo_netinet_firewall_send_t mpo_netinet_firewall_send;
+ mpo_netinet_fragment_t mpo_netinet_fragment;
+ mpo_netinet_icmp_reply_t mpo_netinet_icmp_reply;
+ mpo_netinet_icmp_replyinplace_t mpo_netinet_icmp_replyinplace;
+ mpo_netinet_igmp_send_t mpo_netinet_igmp_send;
+ mpo_netinet_tcp_reply_t mpo_netinet_tcp_reply;
+
+ mpo_netinet6_nd6_send_t mpo_netinet6_nd6_send;
+
+ mpo_pipe_check_ioctl_t mpo_pipe_check_ioctl;
+ mpo_pipe_check_poll_t mpo_pipe_check_poll;
+ mpo_pipe_check_read_t mpo_pipe_check_read;
+ mpo_pipe_check_relabel_t mpo_pipe_check_relabel;
+ mpo_pipe_check_stat_t mpo_pipe_check_stat;
+ mpo_pipe_check_write_t mpo_pipe_check_write;
+ mpo_pipe_copy_label_t mpo_pipe_copy_label;
+ mpo_pipe_create_t mpo_pipe_create;
+ mpo_pipe_destroy_label_t mpo_pipe_destroy_label;
+ mpo_pipe_externalize_label_t mpo_pipe_externalize_label;
+ mpo_pipe_init_label_t mpo_pipe_init_label;
+ mpo_pipe_internalize_label_t mpo_pipe_internalize_label;
+ mpo_pipe_relabel_t mpo_pipe_relabel;
+
+ mpo_posixsem_check_getvalue_t mpo_posixsem_check_getvalue;
+ mpo_posixsem_check_open_t mpo_posixsem_check_open;
+ mpo_posixsem_check_post_t mpo_posixsem_check_post;
+ mpo_posixsem_check_stat_t mpo_posixsem_check_stat;
+ mpo_posixsem_check_unlink_t mpo_posixsem_check_unlink;
+ mpo_posixsem_check_wait_t mpo_posixsem_check_wait;
+ mpo_posixsem_create_t mpo_posixsem_create;
+ mpo_posixsem_destroy_label_t mpo_posixsem_destroy_label;
+ mpo_posixsem_init_label_t mpo_posixsem_init_label;
+
+ mpo_posixshm_check_mmap_t mpo_posixshm_check_mmap;
+ mpo_posixshm_check_open_t mpo_posixshm_check_open;
+ mpo_posixshm_check_stat_t mpo_posixshm_check_stat;
+ mpo_posixshm_check_truncate_t mpo_posixshm_check_truncate;
+ mpo_posixshm_check_unlink_t mpo_posixshm_check_unlink;
+ mpo_posixshm_create_t mpo_posixshm_create;
+ mpo_posixshm_destroy_label_t mpo_posixshm_destroy_label;
+ mpo_posixshm_init_label_t mpo_posixshm_init_label;
+
+ mpo_priv_check_t mpo_priv_check;
+ mpo_priv_grant_t mpo_priv_grant;
+
+ mpo_proc_check_debug_t mpo_proc_check_debug;
+ mpo_proc_check_sched_t mpo_proc_check_sched;
+ mpo_proc_check_setaudit_t mpo_proc_check_setaudit;
+ mpo_proc_check_setaudit_addr_t mpo_proc_check_setaudit_addr;
+ mpo_proc_check_setauid_t mpo_proc_check_setauid;
+ mpo_proc_check_setuid_t mpo_proc_check_setuid;
+ mpo_proc_check_seteuid_t mpo_proc_check_seteuid;
+ mpo_proc_check_setgid_t mpo_proc_check_setgid;
+ mpo_proc_check_setegid_t mpo_proc_check_setegid;
+ mpo_proc_check_setgroups_t mpo_proc_check_setgroups;
+ mpo_proc_check_setreuid_t mpo_proc_check_setreuid;
+ mpo_proc_check_setregid_t mpo_proc_check_setregid;
+ mpo_proc_check_setresuid_t mpo_proc_check_setresuid;
+ mpo_proc_check_setresgid_t mpo_proc_check_setresgid;
+ mpo_proc_check_signal_t mpo_proc_check_signal;
+ mpo_proc_check_wait_t mpo_proc_check_wait;
+ mpo_proc_destroy_label_t mpo_proc_destroy_label;
+ mpo_proc_init_label_t mpo_proc_init_label;
+
+ mpo_socket_check_accept_t mpo_socket_check_accept;
+ mpo_socket_check_bind_t mpo_socket_check_bind;
+ mpo_socket_check_connect_t mpo_socket_check_connect;
+ mpo_socket_check_create_t mpo_socket_check_create;
+ mpo_socket_check_deliver_t mpo_socket_check_deliver;
+ mpo_socket_check_listen_t mpo_socket_check_listen;
+ mpo_socket_check_poll_t mpo_socket_check_poll;
+ mpo_socket_check_receive_t mpo_socket_check_receive;
+ mpo_socket_check_relabel_t mpo_socket_check_relabel;
+ mpo_socket_check_send_t mpo_socket_check_send;
+ mpo_socket_check_stat_t mpo_socket_check_stat;
+ mpo_socket_check_visible_t mpo_socket_check_visible;
+ mpo_socket_copy_label_t mpo_socket_copy_label;
+ mpo_socket_create_t mpo_socket_create;
+ mpo_socket_create_mbuf_t mpo_socket_create_mbuf;
+ mpo_socket_destroy_label_t mpo_socket_destroy_label;
+ mpo_socket_externalize_label_t mpo_socket_externalize_label;
+ mpo_socket_init_label_t mpo_socket_init_label;
+ mpo_socket_internalize_label_t mpo_socket_internalize_label;
+ mpo_socket_newconn_t mpo_socket_newconn;
+ mpo_socket_relabel_t mpo_socket_relabel;
+
+ mpo_socketpeer_destroy_label_t mpo_socketpeer_destroy_label;
+ mpo_socketpeer_externalize_label_t mpo_socketpeer_externalize_label;
+ mpo_socketpeer_init_label_t mpo_socketpeer_init_label;
+ mpo_socketpeer_set_from_mbuf_t mpo_socketpeer_set_from_mbuf;
+ mpo_socketpeer_set_from_socket_t mpo_socketpeer_set_from_socket;
+
+ mpo_syncache_init_label_t mpo_syncache_init_label;
+ mpo_syncache_destroy_label_t mpo_syncache_destroy_label;
+ mpo_syncache_create_t mpo_syncache_create;
+ mpo_syncache_create_mbuf_t mpo_syncache_create_mbuf;
+
+ mpo_system_check_acct_t mpo_system_check_acct;
+ mpo_system_check_audit_t mpo_system_check_audit;
+ mpo_system_check_auditctl_t mpo_system_check_auditctl;
+ mpo_system_check_auditon_t mpo_system_check_auditon;
+ mpo_system_check_reboot_t mpo_system_check_reboot;
+ mpo_system_check_swapon_t mpo_system_check_swapon;
+ mpo_system_check_swapoff_t mpo_system_check_swapoff;
+ mpo_system_check_sysctl_t mpo_system_check_sysctl;
+
+ mpo_sysvmsg_cleanup_t mpo_sysvmsg_cleanup;
+ mpo_sysvmsg_create_t mpo_sysvmsg_create;
+ mpo_sysvmsg_destroy_label_t mpo_sysvmsg_destroy_label;
+ mpo_sysvmsg_init_label_t mpo_sysvmsg_init_label;
+
+ mpo_sysvmsq_check_msgmsq_t mpo_sysvmsq_check_msgmsq;
+ mpo_sysvmsq_check_msgrcv_t mpo_sysvmsq_check_msgrcv;
+ mpo_sysvmsq_check_msgrmid_t mpo_sysvmsq_check_msgrmid;
+ mpo_sysvmsq_check_msqctl_t mpo_sysvmsq_check_msqctl;
+ mpo_sysvmsq_check_msqget_t mpo_sysvmsq_check_msqget;
+ mpo_sysvmsq_check_msqrcv_t mpo_sysvmsq_check_msqrcv;
+ mpo_sysvmsq_check_msqsnd_t mpo_sysvmsq_check_msqsnd;
+ mpo_sysvmsq_cleanup_t mpo_sysvmsq_cleanup;
+ mpo_sysvmsq_create_t mpo_sysvmsq_create;
+ mpo_sysvmsq_destroy_label_t mpo_sysvmsq_destroy_label;
+ mpo_sysvmsq_init_label_t mpo_sysvmsq_init_label;
+
+ mpo_sysvsem_check_semctl_t mpo_sysvsem_check_semctl;
+ mpo_sysvsem_check_semget_t mpo_sysvsem_check_semget;
+ mpo_sysvsem_check_semop_t mpo_sysvsem_check_semop;
+ mpo_sysvsem_cleanup_t mpo_sysvsem_cleanup;
+ mpo_sysvsem_create_t mpo_sysvsem_create;
+ mpo_sysvsem_destroy_label_t mpo_sysvsem_destroy_label;
+ mpo_sysvsem_init_label_t mpo_sysvsem_init_label;
+
+ mpo_sysvshm_check_shmat_t mpo_sysvshm_check_shmat;
+ mpo_sysvshm_check_shmctl_t mpo_sysvshm_check_shmctl;
+ mpo_sysvshm_check_shmdt_t mpo_sysvshm_check_shmdt;
+ mpo_sysvshm_check_shmget_t mpo_sysvshm_check_shmget;
+ mpo_sysvshm_cleanup_t mpo_sysvshm_cleanup;
+ mpo_sysvshm_create_t mpo_sysvshm_create;
+ mpo_sysvshm_destroy_label_t mpo_sysvshm_destroy_label;
+ mpo_sysvshm_init_label_t mpo_sysvshm_init_label;
+
+ mpo_thread_userret_t mpo_thread_userret;
+
+ mpo_vnode_check_access_t mpo_vnode_check_access;
+ mpo_vnode_check_chdir_t mpo_vnode_check_chdir;
+ mpo_vnode_check_chroot_t mpo_vnode_check_chroot;
+ mpo_vnode_check_create_t mpo_vnode_check_create;
+ mpo_vnode_check_deleteacl_t mpo_vnode_check_deleteacl;
+ mpo_vnode_check_deleteextattr_t mpo_vnode_check_deleteextattr;
+ mpo_vnode_check_exec_t mpo_vnode_check_exec;
+ mpo_vnode_check_getacl_t mpo_vnode_check_getacl;
+ mpo_vnode_check_getextattr_t mpo_vnode_check_getextattr;
+ mpo_vnode_check_link_t mpo_vnode_check_link;
+ mpo_vnode_check_listextattr_t mpo_vnode_check_listextattr;
+ mpo_vnode_check_lookup_t mpo_vnode_check_lookup;
+ mpo_vnode_check_mmap_t mpo_vnode_check_mmap;
+ mpo_vnode_check_mmap_downgrade_t mpo_vnode_check_mmap_downgrade;
+ mpo_vnode_check_mprotect_t mpo_vnode_check_mprotect;
+ mpo_vnode_check_open_t mpo_vnode_check_open;
+ mpo_vnode_check_poll_t mpo_vnode_check_poll;
+ mpo_vnode_check_read_t mpo_vnode_check_read;
+ mpo_vnode_check_readdir_t mpo_vnode_check_readdir;
+ mpo_vnode_check_readlink_t mpo_vnode_check_readlink;
+ mpo_vnode_check_relabel_t mpo_vnode_check_relabel;
+ mpo_vnode_check_rename_from_t mpo_vnode_check_rename_from;
+ mpo_vnode_check_rename_to_t mpo_vnode_check_rename_to;
+ mpo_vnode_check_revoke_t mpo_vnode_check_revoke;
+ mpo_vnode_check_setacl_t mpo_vnode_check_setacl;
+ mpo_vnode_check_setextattr_t mpo_vnode_check_setextattr;
+ mpo_vnode_check_setflags_t mpo_vnode_check_setflags;
+ mpo_vnode_check_setmode_t mpo_vnode_check_setmode;
+ mpo_vnode_check_setowner_t mpo_vnode_check_setowner;
+ mpo_vnode_check_setutimes_t mpo_vnode_check_setutimes;
+ mpo_vnode_check_stat_t mpo_vnode_check_stat;
+ mpo_vnode_check_unlink_t mpo_vnode_check_unlink;
+ mpo_vnode_check_write_t mpo_vnode_check_write;
+ mpo_vnode_associate_extattr_t mpo_vnode_associate_extattr;
+ mpo_vnode_associate_singlelabel_t mpo_vnode_associate_singlelabel;
+ mpo_vnode_destroy_label_t mpo_vnode_destroy_label;
+ mpo_vnode_copy_label_t mpo_vnode_copy_label;
+ mpo_vnode_create_extattr_t mpo_vnode_create_extattr;
+ mpo_vnode_execve_transition_t mpo_vnode_execve_transition;
+ mpo_vnode_execve_will_transition_t mpo_vnode_execve_will_transition;
+ mpo_vnode_externalize_label_t mpo_vnode_externalize_label;
+ mpo_vnode_init_label_t mpo_vnode_init_label;
+ mpo_vnode_internalize_label_t mpo_vnode_internalize_label;
+ mpo_vnode_relabel_t mpo_vnode_relabel;
+ mpo_vnode_setlabel_extattr_t mpo_vnode_setlabel_extattr;
+};
+
+/*
+ * struct mac_policy_conf is the registration structure for policies, and is
+ * provided to the MAC Framework using MAC_POLICY_SET() to invoke a SYSINIT
+ * to register the policy. In general, the fields are immutable, with the
+ * exception of the "security field", run-time flags, and policy list entry,
+ * which are managed by the MAC Framework. Be careful when modifying this
+ * structure, as its layout is statically compiled into all policies.
+ */
+struct mac_policy_conf {
+ char *mpc_name; /* policy name */
+ char *mpc_fullname; /* policy full name */
+ struct mac_policy_ops *mpc_ops; /* policy operations */
+ int mpc_loadtime_flags; /* flags */
+ int *mpc_field_off; /* security field */
+ int mpc_runtime_flags; /* flags */
+ int _mpc_spare1; /* Spare. */
+ uint64_t mpc_labeled; /* Labeled objects. */
+ uint64_t _mpc_spare2; /* Spare. */
+ void *_mpc_spare3; /* Spare. */
+ LIST_ENTRY(mac_policy_conf) mpc_list; /* global list */
+};
+
+/* Flags for the mpc_loadtime_flags field. */
+#define MPC_LOADTIME_FLAG_NOTLATE 0x00000001
+#define MPC_LOADTIME_FLAG_UNLOADOK 0x00000002
+
+/* Flags for the mpc_runtime_flags field. */
+#define MPC_RUNTIME_FLAG_REGISTERED 0x00000001
+
+/*
+ * Flags for mpc_labeled declaring which objects should have labels allocated
+ * for them by the MAC Framework.
+ */
+#define MPC_OBJECT_CRED 0x0000000000000001
+#define MPC_OBJECT_PROC 0x0000000000000002
+#define MPC_OBJECT_VNODE 0x0000000000000004
+#define MPC_OBJECT_INPCB 0x0000000000000008
+#define MPC_OBJECT_SOCKET 0x0000000000000010
+#define MPC_OBJECT_DEVFS 0x0000000000000020
+#define MPC_OBJECT_MBUF 0x0000000000000040
+#define MPC_OBJECT_IPQ 0x0000000000000080
+#define MPC_OBJECT_IFNET 0x0000000000000100
+#define MPC_OBJECT_BPFDESC 0x0000000000000200
+#define MPC_OBJECT_PIPE 0x0000000000000400
+#define MPC_OBJECT_MOUNT 0x0000000000000800
+#define MPC_OBJECT_POSIXSEM 0x0000000000001000
+#define MPC_OBJECT_POSIXSHM 0x0000000000002000
+#define MPC_OBJECT_SYSVMSG 0x0000000000004000
+#define MPC_OBJECT_SYSVMSQ 0x0000000000008000
+#define MPC_OBJECT_SYSVSEM 0x0000000000010000
+#define MPC_OBJECT_SYSVSHM 0x0000000000020000
+#define MPC_OBJECT_SYNCACHE 0x0000000000040000
+#define MPC_OBJECT_IP6Q 0x0000000000080000
+
+/*-
+ * The TrustedBSD MAC Framework has a major version number, MAC_VERSION,
+ * which defines the ABI of the Framework present in the kernel (and depended
+ * on by policy modules compiled against that kernel). Currently,
+ * MAC_POLICY_SET() requires that the kernel and module ABI version numbers
+ * exactly match. The following major versions have been defined to date:
+ *
+ * MAC version FreeBSD versions
+ * 1 5.x
+ * 2 6.x
+ * 3 7.x
+ * 4 8.x
+ */
+#define MAC_VERSION 4
+
+#define MAC_POLICY_SET(mpops, mpname, mpfullname, mpflags, privdata_wanted, \
+ labeled) \
+ static struct mac_policy_conf mpname##_mac_policy_conf = { \
+ .mpc_name = #mpname, \
+ .mpc_fullname = mpfullname, \
+ .mpc_ops = mpops, \
+ .mpc_loadtime_flags = mpflags, \
+ .mpc_field_off = privdata_wanted, \
+ .mpc_labeled = labeled, \
+ }; \
+ static moduledata_t mpname##_mod = { \
+ #mpname, \
+ mac_policy_modevent, \
+ &mpname##_mac_policy_conf \
+ }; \
+ MODULE_DEPEND(mpname, kernel_mac_support, MAC_VERSION, \
+ MAC_VERSION, MAC_VERSION); \
+ DECLARE_MODULE(mpname, mpname##_mod, SI_SUB_MAC_POLICY, \
+ SI_ORDER_MIDDLE)
+
+int mac_policy_modevent(module_t mod, int type, void *data);
+
+/*
+ * Policy interface to map a struct label pointer to per-policy data.
+ * Typically, policies wrap this in their own accessor macro that casts a
+ * uintptr_t to a policy-specific data type.
+ */
+intptr_t mac_label_get(struct label *l, int slot);
+void mac_label_set(struct label *l, int slot, intptr_t v);
+
+#endif /* !_SECURITY_MAC_MAC_POLICY_H_ */
diff --git a/sys/security/mac/mac_posix_sem.c b/sys/security/mac/mac_posix_sem.c
new file mode 100644
index 0000000..1cda22c
--- /dev/null
+++ b/sys/security/mac/mac_posix_sem.c
@@ -0,0 +1,164 @@
+/*-
+ * Copyright (c) 2003-2006 SPARTA, Inc.
+ * All rights reserved.
+ *
+ * This software was developed for the FreeBSD Project in part by Network
+ * Associates Laboratories, the Security Research Division of Network
+ * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"),
+ * as part of the DARPA CHATS research program.
+ *
+ * This software was enhanced by SPARTA ISSO under SPAWAR contract
+ * N66001-04-C-6019 ("SEFOS").
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "opt_mac.h"
+#include "opt_posix.h"
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/ksem.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/systm.h>
+#include <sys/sysctl.h>
+
+#include <security/mac/mac_framework.h>
+#include <security/mac/mac_internal.h>
+#include <security/mac/mac_policy.h>
+
+static struct label *
+mac_posixsem_label_alloc(void)
+{
+ struct label *label;
+
+ label = mac_labelzone_alloc(M_WAITOK);
+ MAC_PERFORM(posixsem_init_label, label);
+ return (label);
+}
+
+void
+mac_posixsem_init(struct ksem *ks)
+{
+
+ if (mac_labeled & MPC_OBJECT_POSIXSEM)
+ ks->ks_label = mac_posixsem_label_alloc();
+ else
+ ks->ks_label = NULL;
+}
+
+static void
+mac_posixsem_label_free(struct label *label)
+{
+
+ MAC_PERFORM(posixsem_destroy_label, label);
+ mac_labelzone_free(label);
+}
+
+void
+mac_posixsem_destroy(struct ksem *ks)
+{
+
+ if (ks->ks_label != NULL) {
+ mac_posixsem_label_free(ks->ks_label);
+ ks->ks_label = NULL;
+ }
+}
+
+void
+mac_posixsem_create(struct ucred *cred, struct ksem *ks)
+{
+
+ MAC_PERFORM(posixsem_create, cred, ks, ks->ks_label);
+}
+
+int
+mac_posixsem_check_open(struct ucred *cred, struct ksem *ks)
+{
+ int error;
+
+ MAC_CHECK(posixsem_check_open, cred, ks, ks->ks_label);
+
+ return (error);
+}
+
+int
+mac_posixsem_check_getvalue(struct ucred *active_cred, struct ucred *file_cred,
+ struct ksem *ks)
+{
+ int error;
+
+ MAC_CHECK(posixsem_check_getvalue, active_cred, file_cred, ks,
+ ks->ks_label);
+
+ return (error);
+}
+
+int
+mac_posixsem_check_post(struct ucred *active_cred, struct ucred *file_cred,
+ struct ksem *ks)
+{
+ int error;
+
+ MAC_CHECK(posixsem_check_post, active_cred, file_cred, ks,
+ ks->ks_label);
+
+ return (error);
+}
+
+int
+mac_posixsem_check_stat(struct ucred *active_cred, struct ucred *file_cred,
+ struct ksem *ks)
+{
+ int error;
+
+ MAC_CHECK(posixsem_check_stat, active_cred, file_cred, ks,
+ ks->ks_label);
+
+ return (error);
+}
+
+int
+mac_posixsem_check_unlink(struct ucred *cred, struct ksem *ks)
+{
+ int error;
+
+ MAC_CHECK(posixsem_check_unlink, cred, ks, ks->ks_label);
+
+ return (error);
+}
+
+int
+mac_posixsem_check_wait(struct ucred *active_cred, struct ucred *file_cred,
+ struct ksem *ks)
+{
+ int error;
+
+ MAC_CHECK(posixsem_check_wait, active_cred, file_cred, ks,
+ ks->ks_label);
+
+ return (error);
+}
diff --git a/sys/security/mac/mac_posix_shm.c b/sys/security/mac/mac_posix_shm.c
new file mode 100644
index 0000000..97587ad
--- /dev/null
+++ b/sys/security/mac/mac_posix_shm.c
@@ -0,0 +1,151 @@
+/*-
+ * Copyright (c) 2003-2006 SPARTA, Inc.
+ * All rights reserved.
+ *
+ * This software was developed for the FreeBSD Project in part by Network
+ * Associates Laboratories, the Security Research Division of Network
+ * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"),
+ * as part of the DARPA CHATS research program.
+ *
+ * This software was enhanced by SPARTA ISSO under SPAWAR contract
+ * N66001-04-C-6019 ("SEFOS").
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "opt_mac.h"
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/mman.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/systm.h>
+#include <sys/sysctl.h>
+
+#include <security/mac/mac_framework.h>
+#include <security/mac/mac_internal.h>
+#include <security/mac/mac_policy.h>
+
+static struct label *
+mac_posixshm_label_alloc(void)
+{
+ struct label *label;
+
+ label = mac_labelzone_alloc(M_WAITOK);
+ MAC_PERFORM(posixshm_init_label, label);
+ return (label);
+}
+
+void
+mac_posixshm_init(struct shmfd *shmfd)
+{
+
+ if (mac_labeled & MPC_OBJECT_POSIXSHM)
+ shmfd->shm_label = mac_posixshm_label_alloc();
+ else
+ shmfd->shm_label = NULL;
+}
+
+static void
+mac_posixshm_label_free(struct label *label)
+{
+
+ MAC_PERFORM(posixshm_destroy_label, label);
+ mac_labelzone_free(label);
+}
+
+void
+mac_posixshm_destroy(struct shmfd *shmfd)
+{
+
+ if (shmfd->shm_label != NULL) {
+ mac_posixshm_label_free(shmfd->shm_label);
+ shmfd->shm_label = NULL;
+ }
+}
+
+void
+mac_posixshm_create(struct ucred *cred, struct shmfd *shmfd)
+{
+
+ MAC_PERFORM(posixshm_create, cred, shmfd, shmfd->shm_label);
+}
+
+int
+mac_posixshm_check_mmap(struct ucred *cred, struct shmfd *shmfd, int prot,
+ int flags)
+{
+ int error;
+
+ MAC_CHECK(posixshm_check_mmap, cred, shmfd, shmfd->shm_label, prot,
+ flags);
+
+ return (error);
+}
+
+int
+mac_posixshm_check_open(struct ucred *cred, struct shmfd *shmfd)
+{
+ int error;
+
+ MAC_CHECK(posixshm_check_open, cred, shmfd, shmfd->shm_label);
+
+ return (error);
+}
+
+int
+mac_posixshm_check_stat(struct ucred *active_cred, struct ucred *file_cred,
+ struct shmfd *shmfd)
+{
+ int error;
+
+ MAC_CHECK(posixshm_check_stat, active_cred, file_cred, shmfd,
+ shmfd->shm_label);
+
+ return (error);
+}
+
+int
+mac_posixshm_check_truncate(struct ucred *active_cred, struct ucred *file_cred,
+ struct shmfd *shmfd)
+{
+ int error;
+
+ MAC_CHECK(posixshm_check_truncate, active_cred, file_cred, shmfd,
+ shmfd->shm_label);
+
+ return (error);
+}
+
+int
+mac_posixshm_check_unlink(struct ucred *cred, struct shmfd *shmfd)
+{
+ int error;
+
+ MAC_CHECK(posixshm_check_unlink, cred, shmfd, shmfd->shm_label);
+
+ return (error);
+}
diff --git a/sys/security/mac/mac_priv.c b/sys/security/mac/mac_priv.c
new file mode 100644
index 0000000..45a8c81
--- /dev/null
+++ b/sys/security/mac/mac_priv.c
@@ -0,0 +1,82 @@
+/*-
+ * Copyright (c) 2006 nCircle Network Security, Inc.
+ * All rights reserved.
+ *
+ * This software was developed by Robert N. M. Watson for the TrustedBSD
+ * Project under contract to nCircle Network Security, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR, NCIRCLE NETWORK SECURITY,
+ * INC., OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * MAC checks for system privileges.
+ */
+
+#include "opt_mac.h"
+
+#include <sys/param.h>
+#include <sys/priv.h>
+#include <sys/module.h>
+
+#include <security/mac/mac_framework.h>
+#include <security/mac/mac_internal.h>
+#include <security/mac/mac_policy.h>
+
+/*
+ * The MAC Framework interacts with kernel privilege checks in two ways: it
+ * may restrict the granting of privilege to a subject, and it may grant
+ * additional privileges to the subject. Policies may implement none, one,
+ * or both of these entry points. Restriction of privilege by any policy
+ * always overrides granting of privilege by any policy or other privilege
+ * mechanism. See kern_priv.c:priv_check_cred() for details of the
+ * composition.
+ */
+
+/*
+ * Restrict access to a privilege for a credential. Return failure if any
+ * policy denies access.
+ */
+int
+mac_priv_check(struct ucred *cred, int priv)
+{
+ int error;
+
+ MAC_CHECK(priv_check, cred, priv);
+
+ return (error);
+}
+
+/*
+ * Grant access to a privilege for a credential. Return success if any
+ * policy grants access.
+ */
+int
+mac_priv_grant(struct ucred *cred, int priv)
+{
+ int error;
+
+ MAC_GRANT(priv_grant, cred, priv);
+
+ return (error);
+}
diff --git a/sys/security/mac/mac_process.c b/sys/security/mac/mac_process.c
new file mode 100644
index 0000000..9e95d10
--- /dev/null
+++ b/sys/security/mac/mac_process.c
@@ -0,0 +1,531 @@
+/*-
+ * Copyright (c) 1999-2002, 2008 Robert N. M. Watson
+ * Copyright (c) 2001 Ilmar S. Habibulin
+ * Copyright (c) 2001-2003 Networks Associates Technology, Inc.
+ * Copyright (c) 2005 Samy Al Bahra
+ * Copyright (c) 2006 SPARTA, Inc.
+ * Copyright (c) 2008 Apple Inc.
+ * All rights reserved.
+ *
+ * This software was developed by Robert Watson and Ilmar Habibulin for the
+ * TrustedBSD Project.
+ *
+ * This software was developed for the FreeBSD Project in part by Network
+ * Associates Laboratories, the Security Research Division of Network
+ * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"),
+ * as part of the DARPA CHATS research program.
+ *
+ * This software was enhanced by SPARTA ISSO under SPAWAR contract
+ * N66001-04-C-6019 ("SEFOS").
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "opt_mac.h"
+
+#include <sys/param.h>
+#include <sys/condvar.h>
+#include <sys/imgact.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/mutex.h>
+#include <sys/mac.h>
+#include <sys/proc.h>
+#include <sys/sbuf.h>
+#include <sys/systm.h>
+#include <sys/vnode.h>
+#include <sys/mount.h>
+#include <sys/file.h>
+#include <sys/namei.h>
+#include <sys/sysctl.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+#include <vm/vm_map.h>
+#include <vm/vm_object.h>
+
+#include <security/mac/mac_framework.h>
+#include <security/mac/mac_internal.h>
+#include <security/mac/mac_policy.h>
+
+static int mac_mmap_revocation = 1;
+SYSCTL_INT(_security_mac, OID_AUTO, mmap_revocation, CTLFLAG_RW,
+ &mac_mmap_revocation, 0, "Revoke mmap access to files on subject "
+ "relabel");
+
+static int mac_mmap_revocation_via_cow = 0;
+SYSCTL_INT(_security_mac, OID_AUTO, mmap_revocation_via_cow, CTLFLAG_RW,
+ &mac_mmap_revocation_via_cow, 0, "Revoke mmap access to files via "
+ "copy-on-write semantics, or by removing all write access");
+
+static void mac_proc_vm_revoke_recurse(struct thread *td,
+ struct ucred *cred, struct vm_map *map);
+
+static struct label *
+mac_proc_label_alloc(void)
+{
+ struct label *label;
+
+ label = mac_labelzone_alloc(M_WAITOK);
+ MAC_PERFORM(proc_init_label, label);
+ return (label);
+}
+
+void
+mac_proc_init(struct proc *p)
+{
+
+ if (mac_labeled & MPC_OBJECT_PROC)
+ p->p_label = mac_proc_label_alloc();
+ else
+ p->p_label = NULL;
+}
+
+static void
+mac_proc_label_free(struct label *label)
+{
+
+ MAC_PERFORM(proc_destroy_label, label);
+ mac_labelzone_free(label);
+}
+
+void
+mac_proc_destroy(struct proc *p)
+{
+
+ if (p->p_label != NULL) {
+ mac_proc_label_free(p->p_label);
+ p->p_label = NULL;
+ }
+}
+
+void
+mac_thread_userret(struct thread *td)
+{
+
+ MAC_PERFORM(thread_userret, td);
+}
+
+int
+mac_execve_enter(struct image_params *imgp, struct mac *mac_p)
+{
+ struct label *label;
+ struct mac mac;
+ char *buffer;
+ int error;
+
+ if (mac_p == NULL)
+ return (0);
+
+ if (!(mac_labeled & MPC_OBJECT_CRED))
+ return (EINVAL);
+
+ error = copyin(mac_p, &mac, sizeof(mac));
+ if (error)
+ return (error);
+
+ error = mac_check_structmac_consistent(&mac);
+ if (error)
+ return (error);
+
+ buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
+ error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL);
+ if (error) {
+ free(buffer, M_MACTEMP);
+ return (error);
+ }
+
+ label = mac_cred_label_alloc();
+ error = mac_cred_internalize_label(label, buffer);
+ free(buffer, M_MACTEMP);
+ if (error) {
+ mac_cred_label_free(label);
+ return (error);
+ }
+ imgp->execlabel = label;
+ return (0);
+}
+
+void
+mac_execve_exit(struct image_params *imgp)
+{
+ if (imgp->execlabel != NULL) {
+ mac_cred_label_free(imgp->execlabel);
+ imgp->execlabel = NULL;
+ }
+}
+
+void
+mac_execve_interpreter_enter(struct vnode *interpvp,
+ struct label **interpvplabel)
+{
+
+ if (mac_labeled & MPC_OBJECT_VNODE) {
+ *interpvplabel = mac_vnode_label_alloc();
+ mac_vnode_copy_label(interpvp->v_label, *interpvplabel);
+ } else
+ *interpvplabel = NULL;
+}
+
+void
+mac_execve_interpreter_exit(struct label *interpvplabel)
+{
+
+ if (interpvplabel != NULL)
+ mac_vnode_label_free(interpvplabel);
+}
+
+/*
+ * When relabeling a process, call out to the policies for the maximum
+ * permission allowed for each object type we know about in its memory space,
+ * and revoke access (in the least surprising ways we know) when necessary.
+ * The process lock is not held here.
+ */
+void
+mac_proc_vm_revoke(struct thread *td)
+{
+ struct ucred *cred;
+
+ PROC_LOCK(td->td_proc);
+ cred = crhold(td->td_proc->p_ucred);
+ PROC_UNLOCK(td->td_proc);
+
+ /* XXX freeze all other threads */
+ mac_proc_vm_revoke_recurse(td, cred,
+ &td->td_proc->p_vmspace->vm_map);
+ /* XXX allow other threads to continue */
+
+ crfree(cred);
+}
+
+static __inline const char *
+prot2str(vm_prot_t prot)
+{
+
+ switch (prot & VM_PROT_ALL) {
+ case VM_PROT_READ:
+ return ("r--");
+ case VM_PROT_READ | VM_PROT_WRITE:
+ return ("rw-");
+ case VM_PROT_READ | VM_PROT_EXECUTE:
+ return ("r-x");
+ case VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE:
+ return ("rwx");
+ case VM_PROT_WRITE:
+ return ("-w-");
+ case VM_PROT_EXECUTE:
+ return ("--x");
+ case VM_PROT_WRITE | VM_PROT_EXECUTE:
+ return ("-wx");
+ default:
+ return ("---");
+ }
+}
+
+static void
+mac_proc_vm_revoke_recurse(struct thread *td, struct ucred *cred,
+ struct vm_map *map)
+{
+ struct vm_map_entry *vme;
+ int vfslocked, result;
+ vm_prot_t revokeperms;
+ vm_object_t backing_object, object;
+ vm_ooffset_t offset;
+ struct vnode *vp;
+ struct mount *mp;
+
+ if (!mac_mmap_revocation)
+ return;
+
+ vm_map_lock(map);
+ for (vme = map->header.next; vme != &map->header; vme = vme->next) {
+ if (vme->eflags & MAP_ENTRY_IS_SUB_MAP) {
+ mac_proc_vm_revoke_recurse(td, cred,
+ vme->object.sub_map);
+ continue;
+ }
+ /*
+ * Skip over entries that obviously are not shared.
+ */
+ if (vme->eflags & (MAP_ENTRY_COW | MAP_ENTRY_NOSYNC) ||
+ !vme->max_protection)
+ continue;
+ /*
+ * Drill down to the deepest backing object.
+ */
+ offset = vme->offset;
+ object = vme->object.vm_object;
+ if (object == NULL)
+ continue;
+ VM_OBJECT_LOCK(object);
+ while ((backing_object = object->backing_object) != NULL) {
+ VM_OBJECT_LOCK(backing_object);
+ offset += object->backing_object_offset;
+ VM_OBJECT_UNLOCK(object);
+ object = backing_object;
+ }
+ VM_OBJECT_UNLOCK(object);
+ /*
+ * At the moment, vm_maps and objects aren't considered by
+ * the MAC system, so only things with backing by a normal
+ * object (read: vnodes) are checked.
+ */
+ if (object->type != OBJT_VNODE)
+ continue;
+ vp = (struct vnode *)object->handle;
+ vfslocked = VFS_LOCK_GIANT(vp->v_mount);
+ vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
+ result = vme->max_protection;
+ mac_vnode_check_mmap_downgrade(cred, vp, &result);
+ VOP_UNLOCK(vp, 0);
+ /*
+ * Find out what maximum protection we may be allowing now
+ * but a policy needs to get removed.
+ */
+ revokeperms = vme->max_protection & ~result;
+ if (!revokeperms) {
+ VFS_UNLOCK_GIANT(vfslocked);
+ continue;
+ }
+ printf("pid %ld: revoking %s perms from %#lx:%ld "
+ "(max %s/cur %s)\n", (long)td->td_proc->p_pid,
+ prot2str(revokeperms), (u_long)vme->start,
+ (long)(vme->end - vme->start),
+ prot2str(vme->max_protection), prot2str(vme->protection));
+ /*
+ * This is the really simple case: if a map has more
+ * max_protection than is allowed, but it's not being
+ * actually used (that is, the current protection is still
+ * allowed), we can just wipe it out and do nothing more.
+ */
+ if ((vme->protection & revokeperms) == 0) {
+ vme->max_protection -= revokeperms;
+ } else {
+ if (revokeperms & VM_PROT_WRITE) {
+ /*
+ * In the more complicated case, flush out all
+ * pending changes to the object then turn it
+ * copy-on-write.
+ */
+ vm_object_reference(object);
+ (void) vn_start_write(vp, &mp, V_WAIT);
+ vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
+ VM_OBJECT_LOCK(object);
+ vm_object_page_clean(object,
+ OFF_TO_IDX(offset),
+ OFF_TO_IDX(offset + vme->end - vme->start +
+ PAGE_MASK),
+ OBJPC_SYNC);
+ VM_OBJECT_UNLOCK(object);
+ VOP_UNLOCK(vp, 0);
+ vn_finished_write(mp);
+ vm_object_deallocate(object);
+ /*
+ * Why bother if there's no read permissions
+ * anymore? For the rest, we need to leave
+ * the write permissions on for COW, or
+ * remove them entirely if configured to.
+ */
+ if (!mac_mmap_revocation_via_cow) {
+ vme->max_protection &= ~VM_PROT_WRITE;
+ vme->protection &= ~VM_PROT_WRITE;
+ } if ((revokeperms & VM_PROT_READ) == 0)
+ vme->eflags |= MAP_ENTRY_COW |
+ MAP_ENTRY_NEEDS_COPY;
+ }
+ if (revokeperms & VM_PROT_EXECUTE) {
+ vme->max_protection &= ~VM_PROT_EXECUTE;
+ vme->protection &= ~VM_PROT_EXECUTE;
+ }
+ if (revokeperms & VM_PROT_READ) {
+ vme->max_protection = 0;
+ vme->protection = 0;
+ }
+ pmap_protect(map->pmap, vme->start, vme->end,
+ vme->protection & ~revokeperms);
+ vm_map_simplify_entry(map, vme);
+ }
+ VFS_UNLOCK_GIANT(vfslocked);
+ }
+ vm_map_unlock(map);
+}
+
+int
+mac_proc_check_debug(struct ucred *cred, struct proc *p)
+{
+ int error;
+
+ PROC_LOCK_ASSERT(p, MA_OWNED);
+
+ MAC_CHECK(proc_check_debug, cred, p);
+
+ return (error);
+}
+
+int
+mac_proc_check_sched(struct ucred *cred, struct proc *p)
+{
+ int error;
+
+ PROC_LOCK_ASSERT(p, MA_OWNED);
+
+ MAC_CHECK(proc_check_sched, cred, p);
+
+ return (error);
+}
+
+int
+mac_proc_check_signal(struct ucred *cred, struct proc *p, int signum)
+{
+ int error;
+
+ PROC_LOCK_ASSERT(p, MA_OWNED);
+
+ MAC_CHECK(proc_check_signal, cred, p, signum);
+
+ return (error);
+}
+
+int
+mac_proc_check_setuid(struct proc *p, struct ucred *cred, uid_t uid)
+{
+ int error;
+
+ PROC_LOCK_ASSERT(p, MA_OWNED);
+
+ MAC_CHECK(proc_check_setuid, cred, uid);
+ return (error);
+}
+
+int
+mac_proc_check_seteuid(struct proc *p, struct ucred *cred, uid_t euid)
+{
+ int error;
+
+ PROC_LOCK_ASSERT(p, MA_OWNED);
+
+ MAC_CHECK(proc_check_seteuid, cred, euid);
+ return (error);
+}
+
+int
+mac_proc_check_setgid(struct proc *p, struct ucred *cred, gid_t gid)
+{
+ int error;
+
+ PROC_LOCK_ASSERT(p, MA_OWNED);
+
+ MAC_CHECK(proc_check_setgid, cred, gid);
+
+ return (error);
+}
+
+int
+mac_proc_check_setegid(struct proc *p, struct ucred *cred, gid_t egid)
+{
+ int error;
+
+ PROC_LOCK_ASSERT(p, MA_OWNED);
+
+ MAC_CHECK(proc_check_setegid, cred, egid);
+
+ return (error);
+}
+
+int
+mac_proc_check_setgroups(struct proc *p, struct ucred *cred, int ngroups,
+ gid_t *gidset)
+{
+ int error;
+
+ PROC_LOCK_ASSERT(p, MA_OWNED);
+
+ MAC_CHECK(proc_check_setgroups, cred, ngroups, gidset);
+ return (error);
+}
+
+int
+mac_proc_check_setreuid(struct proc *p, struct ucred *cred, uid_t ruid,
+ uid_t euid)
+{
+ int error;
+
+ PROC_LOCK_ASSERT(p, MA_OWNED);
+
+ MAC_CHECK(proc_check_setreuid, cred, ruid, euid);
+
+ return (error);
+}
+
+int
+mac_proc_check_setregid(struct proc *proc, struct ucred *cred, gid_t rgid,
+ gid_t egid)
+{
+ int error;
+
+ PROC_LOCK_ASSERT(proc, MA_OWNED);
+
+ MAC_CHECK(proc_check_setregid, cred, rgid, egid);
+
+ return (error);
+}
+
+int
+mac_proc_check_setresuid(struct proc *p, struct ucred *cred, uid_t ruid,
+ uid_t euid, uid_t suid)
+{
+ int error;
+
+ PROC_LOCK_ASSERT(p, MA_OWNED);
+
+ MAC_CHECK(proc_check_setresuid, cred, ruid, euid, suid);
+ return (error);
+}
+
+int
+mac_proc_check_setresgid(struct proc *p, struct ucred *cred, gid_t rgid,
+ gid_t egid, gid_t sgid)
+{
+ int error;
+
+ PROC_LOCK_ASSERT(p, MA_OWNED);
+
+ MAC_CHECK(proc_check_setresgid, cred, rgid, egid, sgid);
+
+ return (error);
+}
+
+int
+mac_proc_check_wait(struct ucred *cred, struct proc *p)
+{
+ int error;
+
+ PROC_LOCK_ASSERT(p, MA_OWNED);
+
+ MAC_CHECK(proc_check_wait, cred, p);
+
+ return (error);
+}
diff --git a/sys/security/mac/mac_socket.c b/sys/security/mac/mac_socket.c
new file mode 100644
index 0000000..fe297ce
--- /dev/null
+++ b/sys/security/mac/mac_socket.c
@@ -0,0 +1,571 @@
+/*-
+ * Copyright (c) 1999-2002 Robert N. M. Watson
+ * Copyright (c) 2001 Ilmar S. Habibulin
+ * Copyright (c) 2001-2005 Networks Associates Technology, Inc.
+ * Copyright (c) 2005-2006 SPARTA, Inc.
+ * Copyright (c) 2008 Apple Inc.
+ * All rights reserved.
+ *
+ * This software was developed by Robert Watson and Ilmar Habibulin for the
+ * TrustedBSD Project.
+ *
+ * This software was developed for the FreeBSD Project in part by McAfee
+ * Research, the Technology Research Division of Network Associates, Inc.
+ * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the
+ * DARPA CHATS research program.
+ *
+ * This software was enhanced by SPARTA ISSO under SPAWAR contract
+ * N66001-04-C-6019 ("SEFOS").
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "opt_mac.h"
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/mutex.h>
+#include <sys/mac.h>
+#include <sys/sbuf.h>
+#include <sys/systm.h>
+#include <sys/mount.h>
+#include <sys/file.h>
+#include <sys/namei.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/sysctl.h>
+
+#include <net/bpfdesc.h>
+#include <net/if.h>
+#include <net/if_var.h>
+
+#include <netinet/in.h>
+#include <netinet/in_pcb.h>
+#include <netinet/ip_var.h>
+
+#include <security/mac/mac_framework.h>
+#include <security/mac/mac_internal.h>
+#include <security/mac/mac_policy.h>
+
+/*
+ * Currently, sockets hold two labels: the label of the socket itself, and a
+ * peer label, which may be used by policies to hold a copy of the label of
+ * any remote endpoint.
+ *
+ * Possibly, this peer label should be maintained at the protocol layer
+ * (inpcb, unpcb, etc), as this would allow protocol-aware code to maintain
+ * the label consistently. For example, it might be copied live from a
+ * remote socket for UNIX domain sockets rather than keeping a local copy on
+ * this endpoint, but be cached and updated based on packets received for
+ * TCP/IP.
+ */
+
+struct label *
+mac_socket_label_alloc(int flag)
+{
+ struct label *label;
+ int error;
+
+ label = mac_labelzone_alloc(flag);
+ if (label == NULL)
+ return (NULL);
+
+ MAC_CHECK(socket_init_label, label, flag);
+ if (error) {
+ MAC_PERFORM(socket_destroy_label, label);
+ mac_labelzone_free(label);
+ return (NULL);
+ }
+ return (label);
+}
+
+static struct label *
+mac_socketpeer_label_alloc(int flag)
+{
+ struct label *label;
+ int error;
+
+ label = mac_labelzone_alloc(flag);
+ if (label == NULL)
+ return (NULL);
+
+ MAC_CHECK(socketpeer_init_label, label, flag);
+ if (error) {
+ MAC_PERFORM(socketpeer_destroy_label, label);
+ mac_labelzone_free(label);
+ return (NULL);
+ }
+ return (label);
+}
+
+int
+mac_socket_init(struct socket *so, int flag)
+{
+
+ if (mac_labeled & MPC_OBJECT_SOCKET) {
+ so->so_label = mac_socket_label_alloc(flag);
+ if (so->so_label == NULL)
+ return (ENOMEM);
+ so->so_peerlabel = mac_socketpeer_label_alloc(flag);
+ if (so->so_peerlabel == NULL) {
+ mac_socket_label_free(so->so_label);
+ so->so_label = NULL;
+ return (ENOMEM);
+ }
+ } else {
+ so->so_label = NULL;
+ so->so_peerlabel = NULL;
+ }
+ return (0);
+}
+
+void
+mac_socket_label_free(struct label *label)
+{
+
+ MAC_PERFORM(socket_destroy_label, label);
+ mac_labelzone_free(label);
+}
+
+static void
+mac_socketpeer_label_free(struct label *label)
+{
+
+ MAC_PERFORM(socketpeer_destroy_label, label);
+ mac_labelzone_free(label);
+}
+
+void
+mac_socket_destroy(struct socket *so)
+{
+
+ if (so->so_label != NULL) {
+ mac_socket_label_free(so->so_label);
+ so->so_label = NULL;
+ mac_socketpeer_label_free(so->so_peerlabel);
+ so->so_peerlabel = NULL;
+ }
+}
+
+void
+mac_socket_copy_label(struct label *src, struct label *dest)
+{
+
+ MAC_PERFORM(socket_copy_label, src, dest);
+}
+
+int
+mac_socket_externalize_label(struct label *label, char *elements,
+ char *outbuf, size_t outbuflen)
+{
+ int error;
+
+ MAC_EXTERNALIZE(socket, label, elements, outbuf, outbuflen);
+
+ return (error);
+}
+
+static int
+mac_socketpeer_externalize_label(struct label *label, char *elements,
+ char *outbuf, size_t outbuflen)
+{
+ int error;
+
+ MAC_EXTERNALIZE(socketpeer, label, elements, outbuf, outbuflen);
+
+ return (error);
+}
+
+int
+mac_socket_internalize_label(struct label *label, char *string)
+{
+ int error;
+
+ MAC_INTERNALIZE(socket, label, string);
+
+ return (error);
+}
+
+void
+mac_socket_create(struct ucred *cred, struct socket *so)
+{
+
+ MAC_PERFORM(socket_create, cred, so, so->so_label);
+}
+
+void
+mac_socket_newconn(struct socket *oldso, struct socket *newso)
+{
+
+ SOCK_LOCK_ASSERT(oldso);
+
+ MAC_PERFORM(socket_newconn, oldso, oldso->so_label, newso,
+ newso->so_label);
+}
+
+static void
+mac_socket_relabel(struct ucred *cred, struct socket *so,
+ struct label *newlabel)
+{
+
+ SOCK_LOCK_ASSERT(so);
+
+ MAC_PERFORM(socket_relabel, cred, so, so->so_label, newlabel);
+}
+
+void
+mac_socketpeer_set_from_mbuf(struct mbuf *m, struct socket *so)
+{
+ struct label *label;
+
+ SOCK_LOCK_ASSERT(so);
+
+ label = mac_mbuf_to_label(m);
+
+ MAC_PERFORM(socketpeer_set_from_mbuf, m, label, so,
+ so->so_peerlabel);
+}
+
+void
+mac_socketpeer_set_from_socket(struct socket *oldso, struct socket *newso)
+{
+
+ /*
+ * XXXRW: only hold the socket lock on one at a time, as one socket
+ * is the original, and one is the new. However, it's called in both
+ * directions, so we can't assert the lock here currently.
+ */
+ MAC_PERFORM(socketpeer_set_from_socket, oldso, oldso->so_label,
+ newso, newso->so_peerlabel);
+}
+
+void
+mac_socket_create_mbuf(struct socket *so, struct mbuf *m)
+{
+ struct label *label;
+
+ SOCK_LOCK_ASSERT(so);
+
+ label = mac_mbuf_to_label(m);
+
+ MAC_PERFORM(socket_create_mbuf, so, so->so_label, m, label);
+}
+
+int
+mac_socket_check_accept(struct ucred *cred, struct socket *so)
+{
+ int error;
+
+ SOCK_LOCK_ASSERT(so);
+
+ MAC_CHECK(socket_check_accept, cred, so, so->so_label);
+
+ return (error);
+}
+
+int
+mac_socket_check_bind(struct ucred *ucred, struct socket *so,
+ struct sockaddr *sa)
+{
+ int error;
+
+ SOCK_LOCK_ASSERT(so);
+
+ MAC_CHECK(socket_check_bind, ucred, so, so->so_label, sa);
+
+ return (error);
+}
+
+int
+mac_socket_check_connect(struct ucred *cred, struct socket *so,
+ struct sockaddr *sa)
+{
+ int error;
+
+ SOCK_LOCK_ASSERT(so);
+
+ MAC_CHECK(socket_check_connect, cred, so, so->so_label, sa);
+
+ return (error);
+}
+
+int
+mac_socket_check_create(struct ucred *cred, int domain, int type, int proto)
+{
+ int error;
+
+ MAC_CHECK(socket_check_create, cred, domain, type, proto);
+
+ return (error);
+}
+
+int
+mac_socket_check_deliver(struct socket *so, struct mbuf *m)
+{
+ struct label *label;
+ int error;
+
+ SOCK_LOCK_ASSERT(so);
+
+ label = mac_mbuf_to_label(m);
+
+ MAC_CHECK(socket_check_deliver, so, so->so_label, m, label);
+
+ return (error);
+}
+
+int
+mac_socket_check_listen(struct ucred *cred, struct socket *so)
+{
+ int error;
+
+ SOCK_LOCK_ASSERT(so);
+
+ MAC_CHECK(socket_check_listen, cred, so, so->so_label);
+
+ return (error);
+}
+
+int
+mac_socket_check_poll(struct ucred *cred, struct socket *so)
+{
+ int error;
+
+ SOCK_LOCK_ASSERT(so);
+
+ MAC_CHECK(socket_check_poll, cred, so, so->so_label);
+
+ return (error);
+}
+
+int
+mac_socket_check_receive(struct ucred *cred, struct socket *so)
+{
+ int error;
+
+ SOCK_LOCK_ASSERT(so);
+
+ MAC_CHECK(socket_check_receive, cred, so, so->so_label);
+
+ return (error);
+}
+
+static int
+mac_socket_check_relabel(struct ucred *cred, struct socket *so,
+ struct label *newlabel)
+{
+ int error;
+
+ SOCK_LOCK_ASSERT(so);
+
+ MAC_CHECK(socket_check_relabel, cred, so, so->so_label, newlabel);
+
+ return (error);
+}
+
+int
+mac_socket_check_send(struct ucred *cred, struct socket *so)
+{
+ int error;
+
+ SOCK_LOCK_ASSERT(so);
+
+ MAC_CHECK(socket_check_send, cred, so, so->so_label);
+
+ return (error);
+}
+
+int
+mac_socket_check_stat(struct ucred *cred, struct socket *so)
+{
+ int error;
+
+ SOCK_LOCK_ASSERT(so);
+
+ MAC_CHECK(socket_check_stat, cred, so, so->so_label);
+
+ return (error);
+}
+
+int
+mac_socket_check_visible(struct ucred *cred, struct socket *so)
+{
+ int error;
+
+ SOCK_LOCK_ASSERT(so);
+
+ MAC_CHECK(socket_check_visible, cred, so, so->so_label);
+
+ return (error);
+}
+
+int
+mac_socket_label_set(struct ucred *cred, struct socket *so,
+ struct label *label)
+{
+ int error;
+
+ /*
+ * We acquire the socket lock when we perform the test and set, but
+ * have to release it as the pcb code needs to acquire the pcb lock,
+ * which will precede the socket lock in the lock order. However,
+ * this is fine, as any race will simply result in the inpcb being
+ * refreshed twice, but still consistently, as the inpcb code will
+ * acquire the socket lock before refreshing, holding both locks.
+ */
+ SOCK_LOCK(so);
+ error = mac_socket_check_relabel(cred, so, label);
+ if (error) {
+ SOCK_UNLOCK(so);
+ return (error);
+ }
+
+ mac_socket_relabel(cred, so, label);
+ SOCK_UNLOCK(so);
+
+ /*
+ * If the protocol has expressed interest in socket layer changes,
+ * such as if it needs to propagate changes to a cached pcb label
+ * from the socket, notify it of the label change while holding the
+ * socket lock.
+ */
+ if (so->so_proto->pr_usrreqs->pru_sosetlabel != NULL)
+ (so->so_proto->pr_usrreqs->pru_sosetlabel)(so);
+
+ return (0);
+}
+
+int
+mac_setsockopt_label(struct ucred *cred, struct socket *so, struct mac *mac)
+{
+ struct label *intlabel;
+ char *buffer;
+ int error;
+
+ if (!(mac_labeled & MPC_OBJECT_SOCKET))
+ return (EINVAL);
+
+ error = mac_check_structmac_consistent(mac);
+ if (error)
+ return (error);
+
+ buffer = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK);
+ error = copyinstr(mac->m_string, buffer, mac->m_buflen, NULL);
+ if (error) {
+ free(buffer, M_MACTEMP);
+ return (error);
+ }
+
+ intlabel = mac_socket_label_alloc(M_WAITOK);
+ error = mac_socket_internalize_label(intlabel, buffer);
+ free(buffer, M_MACTEMP);
+ if (error)
+ goto out;
+
+ error = mac_socket_label_set(cred, so, intlabel);
+out:
+ mac_socket_label_free(intlabel);
+ return (error);
+}
+
+int
+mac_getsockopt_label(struct ucred *cred, struct socket *so, struct mac *mac)
+{
+ char *buffer, *elements;
+ struct label *intlabel;
+ int error;
+
+ if (!(mac_labeled & MPC_OBJECT_SOCKET))
+ return (EINVAL);
+
+ error = mac_check_structmac_consistent(mac);
+ if (error)
+ return (error);
+
+ elements = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK);
+ error = copyinstr(mac->m_string, elements, mac->m_buflen, NULL);
+ if (error) {
+ free(elements, M_MACTEMP);
+ return (error);
+ }
+
+ buffer = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
+ intlabel = mac_socket_label_alloc(M_WAITOK);
+ SOCK_LOCK(so);
+ mac_socket_copy_label(so->so_label, intlabel);
+ SOCK_UNLOCK(so);
+ error = mac_socket_externalize_label(intlabel, elements, buffer,
+ mac->m_buflen);
+ mac_socket_label_free(intlabel);
+ if (error == 0)
+ error = copyout(buffer, mac->m_string, strlen(buffer)+1);
+
+ free(buffer, M_MACTEMP);
+ free(elements, M_MACTEMP);
+
+ return (error);
+}
+
+int
+mac_getsockopt_peerlabel(struct ucred *cred, struct socket *so,
+ struct mac *mac)
+{
+ char *elements, *buffer;
+ struct label *intlabel;
+ int error;
+
+ if (!(mac_labeled & MPC_OBJECT_SOCKET))
+ return (EINVAL);
+
+ error = mac_check_structmac_consistent(mac);
+ if (error)
+ return (error);
+
+ elements = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK);
+ error = copyinstr(mac->m_string, elements, mac->m_buflen, NULL);
+ if (error) {
+ free(elements, M_MACTEMP);
+ return (error);
+ }
+
+ buffer = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
+ intlabel = mac_socket_label_alloc(M_WAITOK);
+ SOCK_LOCK(so);
+ mac_socket_copy_label(so->so_peerlabel, intlabel);
+ SOCK_UNLOCK(so);
+ error = mac_socketpeer_externalize_label(intlabel, elements, buffer,
+ mac->m_buflen);
+ mac_socket_label_free(intlabel);
+ if (error == 0)
+ error = copyout(buffer, mac->m_string, strlen(buffer)+1);
+
+ free(buffer, M_MACTEMP);
+ free(elements, M_MACTEMP);
+
+ return (error);
+}
diff --git a/sys/security/mac/mac_syscalls.c b/sys/security/mac/mac_syscalls.c
new file mode 100644
index 0000000..c4b0606
--- /dev/null
+++ b/sys/security/mac/mac_syscalls.c
@@ -0,0 +1,723 @@
+/*-
+ * Copyright (c) 1999-2002, 2006 Robert N. M. Watson
+ * Copyright (c) 2001 Ilmar S. Habibulin
+ * Copyright (c) 2001-2005 Networks Associates Technology, Inc.
+ * Copyright (c) 2005-2006 SPARTA, Inc.
+ * Copyright (c) 2008 Apple Inc.
+ * All rights reserved.
+ *
+ * This software was developed by Robert Watson and Ilmar Habibulin for the
+ * TrustedBSD Project.
+ *
+ * This software was developed for the FreeBSD Project in part by Network
+ * Associates Laboratories, the Security Research Division of Network
+ * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"),
+ * as part of the DARPA CHATS research program.
+ *
+ * This software was enhanced by SPARTA ISSO under SPAWAR contract
+ * N66001-04-C-6019 ("SEFOS").
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "opt_mac.h"
+
+#include <sys/param.h>
+#include <sys/fcntl.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/mutex.h>
+#include <sys/mac.h>
+#include <sys/proc.h>
+#include <sys/systm.h>
+#include <sys/sysproto.h>
+#include <sys/sysent.h>
+#include <sys/vnode.h>
+#include <sys/mount.h>
+#include <sys/file.h>
+#include <sys/namei.h>
+#include <sys/socket.h>
+#include <sys/pipe.h>
+#include <sys/socketvar.h>
+
+#include <security/mac/mac_framework.h>
+#include <security/mac/mac_internal.h>
+#include <security/mac/mac_policy.h>
+
+#ifdef MAC
+
+int
+__mac_get_pid(struct thread *td, struct __mac_get_pid_args *uap)
+{
+ char *elements, *buffer;
+ struct mac mac;
+ struct proc *tproc;
+ struct ucred *tcred;
+ int error;
+
+ error = copyin(uap->mac_p, &mac, sizeof(mac));
+ if (error)
+ return (error);
+
+ error = mac_check_structmac_consistent(&mac);
+ if (error)
+ return (error);
+
+ tproc = pfind(uap->pid);
+ if (tproc == NULL)
+ return (ESRCH);
+
+ tcred = NULL; /* Satisfy gcc. */
+ error = p_cansee(td, tproc);
+ if (error == 0)
+ tcred = crhold(tproc->p_ucred);
+ PROC_UNLOCK(tproc);
+ if (error)
+ return (error);
+
+ elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
+ error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
+ if (error) {
+ free(elements, M_MACTEMP);
+ crfree(tcred);
+ return (error);
+ }
+
+ buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
+ error = mac_cred_externalize_label(tcred->cr_label, elements,
+ buffer, mac.m_buflen);
+ if (error == 0)
+ error = copyout(buffer, mac.m_string, strlen(buffer)+1);
+
+ free(buffer, M_MACTEMP);
+ free(elements, M_MACTEMP);
+ crfree(tcred);
+ return (error);
+}
+
+int
+__mac_get_proc(struct thread *td, struct __mac_get_proc_args *uap)
+{
+ char *elements, *buffer;
+ struct mac mac;
+ int error;
+
+ error = copyin(uap->mac_p, &mac, sizeof(mac));
+ if (error)
+ return (error);
+
+ error = mac_check_structmac_consistent(&mac);
+ if (error)
+ return (error);
+
+ elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
+ error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
+ if (error) {
+ free(elements, M_MACTEMP);
+ return (error);
+ }
+
+ buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
+ error = mac_cred_externalize_label(td->td_ucred->cr_label,
+ elements, buffer, mac.m_buflen);
+ if (error == 0)
+ error = copyout(buffer, mac.m_string, strlen(buffer)+1);
+
+ free(buffer, M_MACTEMP);
+ free(elements, M_MACTEMP);
+ return (error);
+}
+
+int
+__mac_set_proc(struct thread *td, struct __mac_set_proc_args *uap)
+{
+ struct ucred *newcred, *oldcred;
+ struct label *intlabel;
+ struct proc *p;
+ struct mac mac;
+ char *buffer;
+ int error;
+
+ if (!(mac_labeled & MPC_OBJECT_CRED))
+ return (EINVAL);
+
+ error = copyin(uap->mac_p, &mac, sizeof(mac));
+ if (error)
+ return (error);
+
+ error = mac_check_structmac_consistent(&mac);
+ if (error)
+ return (error);
+
+ buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
+ error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL);
+ if (error) {
+ free(buffer, M_MACTEMP);
+ return (error);
+ }
+
+ intlabel = mac_cred_label_alloc();
+ error = mac_cred_internalize_label(intlabel, buffer);
+ free(buffer, M_MACTEMP);
+ if (error)
+ goto out;
+
+ newcred = crget();
+
+ p = td->td_proc;
+ PROC_LOCK(p);
+ oldcred = p->p_ucred;
+
+ error = mac_cred_check_relabel(oldcred, intlabel);
+ if (error) {
+ PROC_UNLOCK(p);
+ crfree(newcred);
+ goto out;
+ }
+
+ setsugid(p);
+ crcopy(newcred, oldcred);
+ mac_cred_relabel(newcred, intlabel);
+ p->p_ucred = newcred;
+
+ PROC_UNLOCK(p);
+ crfree(oldcred);
+ mac_proc_vm_revoke(td);
+
+out:
+ mac_cred_label_free(intlabel);
+ return (error);
+}
+
+int
+__mac_get_fd(struct thread *td, struct __mac_get_fd_args *uap)
+{
+ char *elements, *buffer;
+ struct label *intlabel;
+ struct file *fp;
+ struct mac mac;
+ struct vnode *vp;
+ struct pipe *pipe;
+ struct socket *so;
+ short label_type;
+ int vfslocked, error;
+
+ error = copyin(uap->mac_p, &mac, sizeof(mac));
+ if (error)
+ return (error);
+
+ error = mac_check_structmac_consistent(&mac);
+ if (error)
+ return (error);
+
+ elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
+ error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
+ if (error) {
+ free(elements, M_MACTEMP);
+ return (error);
+ }
+
+ buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
+ error = fget(td, uap->fd, &fp);
+ if (error)
+ goto out;
+
+ label_type = fp->f_type;
+ switch (fp->f_type) {
+ case DTYPE_FIFO:
+ case DTYPE_VNODE:
+ if (!(mac_labeled & MPC_OBJECT_VNODE))
+ return (EINVAL);
+ vp = fp->f_vnode;
+ intlabel = mac_vnode_label_alloc();
+ vfslocked = VFS_LOCK_GIANT(vp->v_mount);
+ vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
+ mac_vnode_copy_label(vp->v_label, intlabel);
+ VOP_UNLOCK(vp, 0);
+ VFS_UNLOCK_GIANT(vfslocked);
+ error = mac_vnode_externalize_label(intlabel, elements,
+ buffer, mac.m_buflen);
+ mac_vnode_label_free(intlabel);
+ break;
+
+ case DTYPE_PIPE:
+ if (!(mac_labeled & MPC_OBJECT_PIPE))
+ return (EINVAL);
+ pipe = fp->f_data;
+ intlabel = mac_pipe_label_alloc();
+ PIPE_LOCK(pipe);
+ mac_pipe_copy_label(pipe->pipe_pair->pp_label, intlabel);
+ PIPE_UNLOCK(pipe);
+ error = mac_pipe_externalize_label(intlabel, elements,
+ buffer, mac.m_buflen);
+ mac_pipe_label_free(intlabel);
+ break;
+
+ case DTYPE_SOCKET:
+ if (!(mac_labeled & MPC_OBJECT_SOCKET))
+ return (EINVAL);
+ so = fp->f_data;
+ intlabel = mac_socket_label_alloc(M_WAITOK);
+ SOCK_LOCK(so);
+ mac_socket_copy_label(so->so_label, intlabel);
+ SOCK_UNLOCK(so);
+ error = mac_socket_externalize_label(intlabel, elements,
+ buffer, mac.m_buflen);
+ mac_socket_label_free(intlabel);
+ break;
+
+ default:
+ error = EINVAL;
+ }
+ fdrop(fp, td);
+ if (error == 0)
+ error = copyout(buffer, mac.m_string, strlen(buffer)+1);
+
+out:
+ free(buffer, M_MACTEMP);
+ free(elements, M_MACTEMP);
+ return (error);
+}
+
+int
+__mac_get_file(struct thread *td, struct __mac_get_file_args *uap)
+{
+ char *elements, *buffer;
+ struct nameidata nd;
+ struct label *intlabel;
+ struct mac mac;
+ int vfslocked, error;
+
+ if (!(mac_labeled & MPC_OBJECT_VNODE))
+ return (EINVAL);
+
+ error = copyin(uap->mac_p, &mac, sizeof(mac));
+ if (error)
+ return (error);
+
+ error = mac_check_structmac_consistent(&mac);
+ if (error)
+ return (error);
+
+ elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
+ error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
+ if (error) {
+ free(elements, M_MACTEMP);
+ return (error);
+ }
+
+ buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
+ NDINIT(&nd, LOOKUP, MPSAFE | LOCKLEAF | FOLLOW, UIO_USERSPACE,
+ uap->path_p, td);
+ error = namei(&nd);
+ if (error)
+ goto out;
+
+ intlabel = mac_vnode_label_alloc();
+ vfslocked = NDHASGIANT(&nd);
+ mac_vnode_copy_label(nd.ni_vp->v_label, intlabel);
+ error = mac_vnode_externalize_label(intlabel, elements, buffer,
+ mac.m_buflen);
+
+ NDFREE(&nd, 0);
+ VFS_UNLOCK_GIANT(vfslocked);
+ mac_vnode_label_free(intlabel);
+ if (error == 0)
+ error = copyout(buffer, mac.m_string, strlen(buffer)+1);
+
+out:
+ free(buffer, M_MACTEMP);
+ free(elements, M_MACTEMP);
+
+ return (error);
+}
+
+int
+__mac_get_link(struct thread *td, struct __mac_get_link_args *uap)
+{
+ char *elements, *buffer;
+ struct nameidata nd;
+ struct label *intlabel;
+ struct mac mac;
+ int vfslocked, error;
+
+ if (!(mac_labeled & MPC_OBJECT_VNODE))
+ return (EINVAL);
+
+ error = copyin(uap->mac_p, &mac, sizeof(mac));
+ if (error)
+ return (error);
+
+ error = mac_check_structmac_consistent(&mac);
+ if (error)
+ return (error);
+
+ elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
+ error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
+ if (error) {
+ free(elements, M_MACTEMP);
+ return (error);
+ }
+
+ buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
+ NDINIT(&nd, LOOKUP, MPSAFE | LOCKLEAF | NOFOLLOW, UIO_USERSPACE,
+ uap->path_p, td);
+ error = namei(&nd);
+ if (error)
+ goto out;
+
+ intlabel = mac_vnode_label_alloc();
+ vfslocked = NDHASGIANT(&nd);
+ mac_vnode_copy_label(nd.ni_vp->v_label, intlabel);
+ error = mac_vnode_externalize_label(intlabel, elements, buffer,
+ mac.m_buflen);
+ NDFREE(&nd, 0);
+ VFS_UNLOCK_GIANT(vfslocked);
+ mac_vnode_label_free(intlabel);
+
+ if (error == 0)
+ error = copyout(buffer, mac.m_string, strlen(buffer)+1);
+
+out:
+ free(buffer, M_MACTEMP);
+ free(elements, M_MACTEMP);
+
+ return (error);
+}
+
+int
+__mac_set_fd(struct thread *td, struct __mac_set_fd_args *uap)
+{
+ struct label *intlabel;
+ struct pipe *pipe;
+ struct socket *so;
+ struct file *fp;
+ struct mount *mp;
+ struct vnode *vp;
+ struct mac mac;
+ char *buffer;
+ int error, vfslocked;
+
+ error = copyin(uap->mac_p, &mac, sizeof(mac));
+ if (error)
+ return (error);
+
+ error = mac_check_structmac_consistent(&mac);
+ if (error)
+ return (error);
+
+ buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
+ error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL);
+ if (error) {
+ free(buffer, M_MACTEMP);
+ return (error);
+ }
+
+ error = fget(td, uap->fd, &fp);
+ if (error)
+ goto out;
+
+ switch (fp->f_type) {
+ case DTYPE_FIFO:
+ case DTYPE_VNODE:
+ if (!(mac_labeled & MPC_OBJECT_VNODE))
+ return (EINVAL);
+ intlabel = mac_vnode_label_alloc();
+ error = mac_vnode_internalize_label(intlabel, buffer);
+ if (error) {
+ mac_vnode_label_free(intlabel);
+ break;
+ }
+ vp = fp->f_vnode;
+ vfslocked = VFS_LOCK_GIANT(vp->v_mount);
+ error = vn_start_write(vp, &mp, V_WAIT | PCATCH);
+ if (error != 0) {
+ VFS_UNLOCK_GIANT(vfslocked);
+ mac_vnode_label_free(intlabel);
+ break;
+ }
+ vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
+ error = vn_setlabel(vp, intlabel, td->td_ucred);
+ VOP_UNLOCK(vp, 0);
+ vn_finished_write(mp);
+ VFS_UNLOCK_GIANT(vfslocked);
+ mac_vnode_label_free(intlabel);
+ break;
+
+ case DTYPE_PIPE:
+ if (!(mac_labeled & MPC_OBJECT_PIPE))
+ return (EINVAL);
+ intlabel = mac_pipe_label_alloc();
+ error = mac_pipe_internalize_label(intlabel, buffer);
+ if (error == 0) {
+ pipe = fp->f_data;
+ PIPE_LOCK(pipe);
+ error = mac_pipe_label_set(td->td_ucred,
+ pipe->pipe_pair, intlabel);
+ PIPE_UNLOCK(pipe);
+ }
+ mac_pipe_label_free(intlabel);
+ break;
+
+ case DTYPE_SOCKET:
+ if (!(mac_labeled & MPC_OBJECT_SOCKET))
+ return (EINVAL);
+ intlabel = mac_socket_label_alloc(M_WAITOK);
+ error = mac_socket_internalize_label(intlabel, buffer);
+ if (error == 0) {
+ so = fp->f_data;
+ error = mac_socket_label_set(td->td_ucred, so,
+ intlabel);
+ }
+ mac_socket_label_free(intlabel);
+ break;
+
+ default:
+ error = EINVAL;
+ }
+ fdrop(fp, td);
+out:
+ free(buffer, M_MACTEMP);
+ return (error);
+}
+
+int
+__mac_set_file(struct thread *td, struct __mac_set_file_args *uap)
+{
+ struct label *intlabel;
+ struct nameidata nd;
+ struct mount *mp;
+ struct mac mac;
+ char *buffer;
+ int vfslocked, error;
+
+ if (!(mac_labeled & MPC_OBJECT_VNODE))
+ return (EINVAL);
+
+ error = copyin(uap->mac_p, &mac, sizeof(mac));
+ if (error)
+ return (error);
+
+ error = mac_check_structmac_consistent(&mac);
+ if (error)
+ return (error);
+
+ buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
+ error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL);
+ if (error) {
+ free(buffer, M_MACTEMP);
+ return (error);
+ }
+
+ intlabel = mac_vnode_label_alloc();
+ error = mac_vnode_internalize_label(intlabel, buffer);
+ free(buffer, M_MACTEMP);
+ if (error)
+ goto out;
+
+ NDINIT(&nd, LOOKUP, MPSAFE | LOCKLEAF | FOLLOW, UIO_USERSPACE,
+ uap->path_p, td);
+ error = namei(&nd);
+ vfslocked = NDHASGIANT(&nd);
+ if (error == 0) {
+ error = vn_start_write(nd.ni_vp, &mp, V_WAIT | PCATCH);
+ if (error == 0) {
+ error = vn_setlabel(nd.ni_vp, intlabel,
+ td->td_ucred);
+ vn_finished_write(mp);
+ }
+ }
+
+ NDFREE(&nd, 0);
+ VFS_UNLOCK_GIANT(vfslocked);
+out:
+ mac_vnode_label_free(intlabel);
+ return (error);
+}
+
+int
+__mac_set_link(struct thread *td, struct __mac_set_link_args *uap)
+{
+ struct label *intlabel;
+ struct nameidata nd;
+ struct mount *mp;
+ struct mac mac;
+ char *buffer;
+ int vfslocked, error;
+
+ if (!(mac_labeled & MPC_OBJECT_VNODE))
+ return (EINVAL);
+
+ error = copyin(uap->mac_p, &mac, sizeof(mac));
+ if (error)
+ return (error);
+
+ error = mac_check_structmac_consistent(&mac);
+ if (error)
+ return (error);
+
+ buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
+ error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL);
+ if (error) {
+ free(buffer, M_MACTEMP);
+ return (error);
+ }
+
+ intlabel = mac_vnode_label_alloc();
+ error = mac_vnode_internalize_label(intlabel, buffer);
+ free(buffer, M_MACTEMP);
+ if (error)
+ goto out;
+
+ NDINIT(&nd, LOOKUP, MPSAFE | LOCKLEAF | NOFOLLOW, UIO_USERSPACE,
+ uap->path_p, td);
+ error = namei(&nd);
+ vfslocked = NDHASGIANT(&nd);
+ if (error == 0) {
+ error = vn_start_write(nd.ni_vp, &mp, V_WAIT | PCATCH);
+ if (error == 0) {
+ error = vn_setlabel(nd.ni_vp, intlabel,
+ td->td_ucred);
+ vn_finished_write(mp);
+ }
+ }
+
+ NDFREE(&nd, 0);
+ VFS_UNLOCK_GIANT(vfslocked);
+out:
+ mac_vnode_label_free(intlabel);
+ return (error);
+}
+
+int
+mac_syscall(struct thread *td, struct mac_syscall_args *uap)
+{
+ struct mac_policy_conf *mpc;
+ char target[MAC_MAX_POLICY_NAME];
+ int entrycount, error;
+
+ error = copyinstr(uap->policy, target, sizeof(target), NULL);
+ if (error)
+ return (error);
+
+ error = ENOSYS;
+ LIST_FOREACH(mpc, &mac_static_policy_list, mpc_list) {
+ if (strcmp(mpc->mpc_name, target) == 0 &&
+ mpc->mpc_ops->mpo_syscall != NULL) {
+ error = mpc->mpc_ops->mpo_syscall(td,
+ uap->call, uap->arg);
+ goto out;
+ }
+ }
+
+ if ((entrycount = mac_policy_list_conditional_busy()) != 0) {
+ LIST_FOREACH(mpc, &mac_policy_list, mpc_list) {
+ if (strcmp(mpc->mpc_name, target) == 0 &&
+ mpc->mpc_ops->mpo_syscall != NULL) {
+ error = mpc->mpc_ops->mpo_syscall(td,
+ uap->call, uap->arg);
+ break;
+ }
+ }
+ mac_policy_list_unbusy();
+ }
+out:
+ return (error);
+}
+
+#else /* !MAC */
+
+int
+__mac_get_pid(struct thread *td, struct __mac_get_pid_args *uap)
+{
+
+ return (ENOSYS);
+}
+
+int
+__mac_get_proc(struct thread *td, struct __mac_get_proc_args *uap)
+{
+
+ return (ENOSYS);
+}
+
+int
+__mac_set_proc(struct thread *td, struct __mac_set_proc_args *uap)
+{
+
+ return (ENOSYS);
+}
+
+int
+__mac_get_fd(struct thread *td, struct __mac_get_fd_args *uap)
+{
+
+ return (ENOSYS);
+}
+
+int
+__mac_get_file(struct thread *td, struct __mac_get_file_args *uap)
+{
+
+ return (ENOSYS);
+}
+
+int
+__mac_get_link(struct thread *td, struct __mac_get_link_args *uap)
+{
+
+ return (ENOSYS);
+}
+
+int
+__mac_set_fd(struct thread *td, struct __mac_set_fd_args *uap)
+{
+
+ return (ENOSYS);
+}
+
+int
+__mac_set_file(struct thread *td, struct __mac_set_file_args *uap)
+{
+
+ return (ENOSYS);
+}
+
+int
+__mac_set_link(struct thread *td, struct __mac_set_link_args *uap)
+{
+
+ return (ENOSYS);
+}
+
+int
+mac_syscall(struct thread *td, struct mac_syscall_args *uap)
+{
+
+ return (ENOSYS);
+}
+
+#endif /* !MAC */
diff --git a/sys/security/mac/mac_system.c b/sys/security/mac/mac_system.c
new file mode 100644
index 0000000..588e019
--- /dev/null
+++ b/sys/security/mac/mac_system.c
@@ -0,0 +1,191 @@
+/*-
+ * Copyright (c) 2002-2003 Networks Associates Technology, Inc.
+ * Copyright (c) 2006 SPARTA, Inc.
+ * Copyright (c) 2007 Robert N. M. Watson
+ * All rights reserved.
+ *
+ * This software was developed for the FreeBSD Project in part by Network
+ * Associates Laboratories, the Security Research Division of Network
+ * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"),
+ * as part of the DARPA CHATS research program.
+ *
+ * Portions of this software were developed by Robert Watson for the
+ * TrustedBSD Project.
+ *
+ * This software was enhanced by SPARTA ISSO under SPAWAR contract
+ * N66001-04-C-6019 ("SEFOS").
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * MAC Framework entry points relating to overall operation of system,
+ * including global services such as the kernel environment and loadable
+ * modules.
+ *
+ * System checks often align with existing privilege checks, but provide
+ * additional security context that may be relevant to policies, such as the
+ * specific object being operated on.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "opt_mac.h"
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/systm.h>
+#include <sys/vnode.h>
+#include <sys/sysctl.h>
+
+#include <security/mac/mac_framework.h>
+#include <security/mac/mac_internal.h>
+#include <security/mac/mac_policy.h>
+
+int
+mac_kenv_check_dump(struct ucred *cred)
+{
+ int error;
+
+ MAC_CHECK(kenv_check_dump, cred);
+
+ return (error);
+}
+
+int
+mac_kenv_check_get(struct ucred *cred, char *name)
+{
+ int error;
+
+ MAC_CHECK(kenv_check_get, cred, name);
+
+ return (error);
+}
+
+int
+mac_kenv_check_set(struct ucred *cred, char *name, char *value)
+{
+ int error;
+
+ MAC_CHECK(kenv_check_set, cred, name, value);
+
+ return (error);
+}
+
+int
+mac_kenv_check_unset(struct ucred *cred, char *name)
+{
+ int error;
+
+ MAC_CHECK(kenv_check_unset, cred, name);
+
+ return (error);
+}
+
+int
+mac_kld_check_load(struct ucred *cred, struct vnode *vp)
+{
+ int error;
+
+ ASSERT_VOP_LOCKED(vp, "mac_kld_check_load");
+
+ MAC_CHECK(kld_check_load, cred, vp, vp->v_label);
+
+ return (error);
+}
+
+int
+mac_kld_check_stat(struct ucred *cred)
+{
+ int error;
+
+ MAC_CHECK(kld_check_stat, cred);
+
+ return (error);
+}
+
+int
+mac_system_check_acct(struct ucred *cred, struct vnode *vp)
+{
+ int error;
+
+ if (vp != NULL) {
+ ASSERT_VOP_LOCKED(vp, "mac_system_check_acct");
+ }
+
+ MAC_CHECK(system_check_acct, cred, vp,
+ vp != NULL ? vp->v_label : NULL);
+
+ return (error);
+}
+
+int
+mac_system_check_reboot(struct ucred *cred, int howto)
+{
+ int error;
+
+ MAC_CHECK(system_check_reboot, cred, howto);
+
+ return (error);
+}
+
+int
+mac_system_check_swapon(struct ucred *cred, struct vnode *vp)
+{
+ int error;
+
+ ASSERT_VOP_LOCKED(vp, "mac_system_check_swapon");
+
+ MAC_CHECK(system_check_swapon, cred, vp, vp->v_label);
+ return (error);
+}
+
+int
+mac_system_check_swapoff(struct ucred *cred, struct vnode *vp)
+{
+ int error;
+
+ ASSERT_VOP_LOCKED(vp, "mac_system_check_swapoff");
+
+ MAC_CHECK(system_check_swapoff, cred, vp, vp->v_label);
+ return (error);
+}
+
+int
+mac_system_check_sysctl(struct ucred *cred, struct sysctl_oid *oidp,
+ void *arg1, int arg2, struct sysctl_req *req)
+{
+ int error;
+
+ /*
+ * XXXMAC: We would very much like to assert the SYSCTL_LOCK here,
+ * but since it's not exported from kern_sysctl.c, we can't.
+ */
+ MAC_CHECK(system_check_sysctl, cred, oidp, arg1, arg2, req);
+
+ return (error);
+}
diff --git a/sys/security/mac/mac_sysv_msg.c b/sys/security/mac/mac_sysv_msg.c
new file mode 100644
index 0000000..2c5bbca
--- /dev/null
+++ b/sys/security/mac/mac_sysv_msg.c
@@ -0,0 +1,237 @@
+/*-
+ * Copyright (c) 2003-2004 Networks Associates Technology, Inc.
+ * Copyright (c) 2006 SPARTA, Inc.
+ * Copyright (c) 2008 Apple Inc.
+ * All rights reserved.
+ *
+ * This software was developed for the FreeBSD Project in part by Network
+ * Associates Laboratories, the Security Research Division of Network
+ * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"),
+ * as part of the DARPA CHATS research program.
+ *
+ * This software was enhanced by SPARTA ISSO under SPAWAR contract
+ * N66001-04-C-6019 ("SEFOS").
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "opt_mac.h"
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/mutex.h>
+#include <sys/sbuf.h>
+#include <sys/systm.h>
+#include <sys/vnode.h>
+#include <sys/mount.h>
+#include <sys/file.h>
+#include <sys/namei.h>
+#include <sys/sysctl.h>
+#include <sys/msg.h>
+
+#include <security/mac/mac_framework.h>
+#include <security/mac/mac_internal.h>
+#include <security/mac/mac_policy.h>
+
+static struct label *
+mac_sysv_msgmsg_label_alloc(void)
+{
+ struct label *label;
+
+ label = mac_labelzone_alloc(M_WAITOK);
+ MAC_PERFORM(sysvmsg_init_label, label);
+ return (label);
+}
+
+void
+mac_sysvmsg_init(struct msg *msgptr)
+{
+
+ if (mac_labeled & MPC_OBJECT_SYSVMSG)
+ msgptr->label = mac_sysv_msgmsg_label_alloc();
+ else
+ msgptr->label = NULL;
+}
+
+static struct label *
+mac_sysv_msgqueue_label_alloc(void)
+{
+ struct label *label;
+
+ label = mac_labelzone_alloc(M_WAITOK);
+ MAC_PERFORM(sysvmsq_init_label, label);
+ return (label);
+}
+
+void
+mac_sysvmsq_init(struct msqid_kernel *msqkptr)
+{
+
+ if (mac_labeled & MPC_OBJECT_SYSVMSQ)
+ msqkptr->label = mac_sysv_msgqueue_label_alloc();
+ else
+ msqkptr->label = NULL;
+}
+
+static void
+mac_sysv_msgmsg_label_free(struct label *label)
+{
+
+ MAC_PERFORM(sysvmsg_destroy_label, label);
+ mac_labelzone_free(label);
+}
+
+void
+mac_sysvmsg_destroy(struct msg *msgptr)
+{
+
+ if (msgptr->label != NULL) {
+ mac_sysv_msgmsg_label_free(msgptr->label);
+ msgptr->label = NULL;
+ }
+}
+
+static void
+mac_sysv_msgqueue_label_free(struct label *label)
+{
+
+ MAC_PERFORM(sysvmsq_destroy_label, label);
+ mac_labelzone_free(label);
+}
+
+void
+mac_sysvmsq_destroy(struct msqid_kernel *msqkptr)
+{
+
+ if (msqkptr->label != NULL) {
+ mac_sysv_msgqueue_label_free(msqkptr->label);
+ msqkptr->label = NULL;
+ }
+}
+
+void
+mac_sysvmsg_create(struct ucred *cred, struct msqid_kernel *msqkptr,
+ struct msg *msgptr)
+{
+
+ MAC_PERFORM(sysvmsg_create, cred, msqkptr, msqkptr->label,
+ msgptr, msgptr->label);
+}
+
+void
+mac_sysvmsq_create(struct ucred *cred, struct msqid_kernel *msqkptr)
+{
+
+ MAC_PERFORM(sysvmsq_create, cred, msqkptr, msqkptr->label);
+}
+
+void
+mac_sysvmsg_cleanup(struct msg *msgptr)
+{
+
+ MAC_PERFORM(sysvmsg_cleanup, msgptr->label);
+}
+
+void
+mac_sysvmsq_cleanup(struct msqid_kernel *msqkptr)
+{
+
+ MAC_PERFORM(sysvmsq_cleanup, msqkptr->label);
+}
+
+int
+mac_sysvmsq_check_msgmsq(struct ucred *cred, struct msg *msgptr,
+ struct msqid_kernel *msqkptr)
+{
+ int error;
+
+ MAC_CHECK(sysvmsq_check_msgmsq, cred, msgptr, msgptr->label,
+ msqkptr, msqkptr->label);
+
+ return (error);
+}
+
+int
+mac_sysvmsq_check_msgrcv(struct ucred *cred, struct msg *msgptr)
+{
+ int error;
+
+ MAC_CHECK(sysvmsq_check_msgrcv, cred, msgptr, msgptr->label);
+
+ return (error);
+}
+
+int
+mac_sysvmsq_check_msgrmid(struct ucred *cred, struct msg *msgptr)
+{
+ int error;
+
+ MAC_CHECK(sysvmsq_check_msgrmid, cred, msgptr, msgptr->label);
+
+ return (error);
+}
+
+int
+mac_sysvmsq_check_msqget(struct ucred *cred, struct msqid_kernel *msqkptr)
+{
+ int error;
+
+ MAC_CHECK(sysvmsq_check_msqget, cred, msqkptr, msqkptr->label);
+
+ return (error);
+}
+
+int
+mac_sysvmsq_check_msqsnd(struct ucred *cred, struct msqid_kernel *msqkptr)
+{
+ int error;
+
+ MAC_CHECK(sysvmsq_check_msqsnd, cred, msqkptr, msqkptr->label);
+
+ return (error);
+}
+
+int
+mac_sysvmsq_check_msqrcv(struct ucred *cred, struct msqid_kernel *msqkptr)
+{
+ int error;
+
+ MAC_CHECK(sysvmsq_check_msqrcv, cred, msqkptr, msqkptr->label);
+
+ return (error);
+}
+
+int
+mac_sysvmsq_check_msqctl(struct ucred *cred, struct msqid_kernel *msqkptr,
+ int cmd)
+{
+ int error;
+
+ MAC_CHECK(sysvmsq_check_msqctl, cred, msqkptr, msqkptr->label, cmd);
+
+ return (error);
+}
diff --git a/sys/security/mac/mac_sysv_sem.c b/sys/security/mac/mac_sysv_sem.c
new file mode 100644
index 0000000..94a1107
--- /dev/null
+++ b/sys/security/mac/mac_sysv_sem.c
@@ -0,0 +1,143 @@
+/*-
+ * Copyright (c) 2003-2004 Networks Associates Technology, Inc.
+ * Copyright (c) 2006 SPARTA, Inc.
+ * All rights reserved.
+ *
+ * This software was developed for the FreeBSD Project in part by Network
+ * Associates Laboratories, the Security Research Division of Network
+ * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"),
+ * as part of the DARPA CHATS research program.
+ *
+ * This software was enhanced by SPARTA ISSO under SPAWAR contract
+ * N66001-04-C-6019 ("SEFOS").
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "opt_mac.h"
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/mutex.h>
+#include <sys/sbuf.h>
+#include <sys/systm.h>
+#include <sys/vnode.h>
+#include <sys/mount.h>
+#include <sys/file.h>
+#include <sys/namei.h>
+#include <sys/sysctl.h>
+#include <sys/sem.h>
+
+#include <security/mac/mac_framework.h>
+#include <security/mac/mac_internal.h>
+#include <security/mac/mac_policy.h>
+
+static struct label *
+mac_sysv_sem_label_alloc(void)
+{
+ struct label *label;
+
+ label = mac_labelzone_alloc(M_WAITOK);
+ MAC_PERFORM(sysvsem_init_label, label);
+ return (label);
+}
+
+void
+mac_sysvsem_init(struct semid_kernel *semakptr)
+{
+
+ if (mac_labeled & MPC_OBJECT_SYSVSEM)
+ semakptr->label = mac_sysv_sem_label_alloc();
+ else
+ semakptr->label = NULL;
+}
+
+static void
+mac_sysv_sem_label_free(struct label *label)
+{
+
+ MAC_PERFORM(sysvsem_destroy_label, label);
+ mac_labelzone_free(label);
+}
+
+void
+mac_sysvsem_destroy(struct semid_kernel *semakptr)
+{
+
+ if (semakptr->label != NULL) {
+ mac_sysv_sem_label_free(semakptr->label);
+ semakptr->label = NULL;
+ }
+}
+
+void
+mac_sysvsem_create(struct ucred *cred, struct semid_kernel *semakptr)
+{
+
+ MAC_PERFORM(sysvsem_create, cred, semakptr, semakptr->label);
+}
+
+void
+mac_sysvsem_cleanup(struct semid_kernel *semakptr)
+{
+
+ MAC_PERFORM(sysvsem_cleanup, semakptr->label);
+}
+
+int
+mac_sysvsem_check_semctl(struct ucred *cred, struct semid_kernel *semakptr,
+ int cmd)
+{
+ int error;
+
+ MAC_CHECK(sysvsem_check_semctl, cred, semakptr, semakptr->label,
+ cmd);
+
+ return (error);
+}
+
+int
+mac_sysvsem_check_semget(struct ucred *cred, struct semid_kernel *semakptr)
+{
+ int error;
+
+ MAC_CHECK(sysvsem_check_semget, cred, semakptr, semakptr->label);
+
+ return (error);
+}
+
+int
+mac_sysvsem_check_semop(struct ucred *cred, struct semid_kernel *semakptr,
+ size_t accesstype)
+{
+ int error;
+
+ MAC_CHECK(sysvsem_check_semop, cred, semakptr, semakptr->label,
+ accesstype);
+
+ return (error);
+}
diff --git a/sys/security/mac/mac_sysv_shm.c b/sys/security/mac/mac_sysv_shm.c
new file mode 100644
index 0000000..950c23e
--- /dev/null
+++ b/sys/security/mac/mac_sysv_shm.c
@@ -0,0 +1,155 @@
+/*-
+ * Copyright (c) 2003-2004 Networks Associates Technology, Inc.
+ * Copyright (c) 2006 SPARTA, Inc.
+ * All rights reserved.
+ *
+ * This software was developed for the FreeBSD Project in part by Network
+ * Associates Laboratories, the Security Research Division of Network
+ * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"),
+ * as part of the DARPA CHATS research program.
+ *
+ * This software was enhanced by SPARTA ISSO under SPAWAR contract
+ * N66001-04-C-6019 ("SEFOS").
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "opt_mac.h"
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/mutex.h>
+#include <sys/sbuf.h>
+#include <sys/systm.h>
+#include <sys/vnode.h>
+#include <sys/mount.h>
+#include <sys/file.h>
+#include <sys/namei.h>
+#include <sys/sysctl.h>
+#include <sys/shm.h>
+
+#include <security/mac/mac_framework.h>
+#include <security/mac/mac_internal.h>
+#include <security/mac/mac_policy.h>
+
+static struct label *
+mac_sysv_shm_label_alloc(void)
+{
+ struct label *label;
+
+ label = mac_labelzone_alloc(M_WAITOK);
+ MAC_PERFORM(sysvshm_init_label, label);
+ return (label);
+}
+
+void
+mac_sysvshm_init(struct shmid_kernel *shmsegptr)
+{
+
+ if (mac_labeled & MPC_OBJECT_SYSVSHM)
+ shmsegptr->label = mac_sysv_shm_label_alloc();
+ else
+ shmsegptr->label = NULL;
+}
+
+static void
+mac_sysv_shm_label_free(struct label *label)
+{
+
+ MAC_PERFORM(sysvshm_destroy_label, label);
+ mac_labelzone_free(label);
+}
+
+void
+mac_sysvshm_destroy(struct shmid_kernel *shmsegptr)
+{
+
+ if (shmsegptr->label != NULL) {
+ mac_sysv_shm_label_free(shmsegptr->label);
+ shmsegptr->label = NULL;
+ }
+}
+
+void
+mac_sysvshm_create(struct ucred *cred, struct shmid_kernel *shmsegptr)
+{
+
+ MAC_PERFORM(sysvshm_create, cred, shmsegptr, shmsegptr->label);
+}
+
+void
+mac_sysvshm_cleanup(struct shmid_kernel *shmsegptr)
+{
+
+ MAC_PERFORM(sysvshm_cleanup, shmsegptr->label);
+}
+
+int
+mac_sysvshm_check_shmat(struct ucred *cred, struct shmid_kernel *shmsegptr,
+ int shmflg)
+{
+ int error;
+
+ MAC_CHECK(sysvshm_check_shmat, cred, shmsegptr, shmsegptr->label,
+ shmflg);
+
+ return (error);
+}
+
+int
+mac_sysvshm_check_shmctl(struct ucred *cred, struct shmid_kernel *shmsegptr,
+ int cmd)
+{
+ int error;
+
+ MAC_CHECK(sysvshm_check_shmctl, cred, shmsegptr, shmsegptr->label,
+ cmd);
+
+ return (error);
+}
+
+int
+mac_sysvshm_check_shmdt(struct ucred *cred, struct shmid_kernel *shmsegptr)
+{
+ int error;
+
+ MAC_CHECK(sysvshm_check_shmdt, cred, shmsegptr, shmsegptr->label);
+
+ return (error);
+}
+
+int
+mac_sysvshm_check_shmget(struct ucred *cred, struct shmid_kernel *shmsegptr,
+ int shmflg)
+{
+ int error;
+
+ MAC_CHECK(sysvshm_check_shmget, cred, shmsegptr, shmsegptr->label,
+ shmflg);
+
+ return (error);
+}
diff --git a/sys/security/mac/mac_vfs.c b/sys/security/mac/mac_vfs.c
new file mode 100644
index 0000000..42da76c
--- /dev/null
+++ b/sys/security/mac/mac_vfs.c
@@ -0,0 +1,894 @@
+/*-
+ * Copyright (c) 1999-2002 Robert N. M. Watson
+ * Copyright (c) 2001 Ilmar S. Habibulin
+ * Copyright (c) 2001-2005 McAfee, Inc.
+ * Copyright (c) 2005-2006 SPARTA, Inc.
+ * Copyright (c) 2008 Apple Inc.
+ * All rights reserved.
+ *
+ * This software was developed by Robert Watson and Ilmar Habibulin for the
+ * TrustedBSD Project.
+ *
+ * This software was developed for the FreeBSD Project in part by McAfee
+ * Research, the Security Research Division of McAfee, Inc. under
+ * DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA
+ * CHATS research program.
+ *
+ * This software was enhanced by SPARTA ISSO under SPAWAR contract
+ * N66001-04-C-6019 ("SEFOS").
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "opt_mac.h"
+
+#include <sys/param.h>
+#include <sys/condvar.h>
+#include <sys/extattr.h>
+#include <sys/imgact.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/mutex.h>
+#include <sys/proc.h>
+#include <sys/sbuf.h>
+#include <sys/systm.h>
+#include <sys/vnode.h>
+#include <sys/mount.h>
+#include <sys/file.h>
+#include <sys/namei.h>
+#include <sys/sysctl.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+#include <vm/vm_map.h>
+#include <vm/vm_object.h>
+
+#include <fs/devfs/devfs.h>
+
+#include <security/mac/mac_framework.h>
+#include <security/mac/mac_internal.h>
+#include <security/mac/mac_policy.h>
+
+/*
+ * Warn about EA transactions only the first time they happen. No locking on
+ * this variable.
+ */
+static int ea_warn_once = 0;
+
+static int mac_vnode_setlabel_extattr(struct ucred *cred,
+ struct vnode *vp, struct label *intlabel);
+
+static struct label *
+mac_devfs_label_alloc(void)
+{
+ struct label *label;
+
+ label = mac_labelzone_alloc(M_WAITOK);
+ MAC_PERFORM(devfs_init_label, label);
+ return (label);
+}
+
+void
+mac_devfs_init(struct devfs_dirent *de)
+{
+
+ if (mac_labeled & MPC_OBJECT_DEVFS)
+ de->de_label = mac_devfs_label_alloc();
+ else
+ de->de_label = NULL;
+}
+
+static struct label *
+mac_mount_label_alloc(void)
+{
+ struct label *label;
+
+ label = mac_labelzone_alloc(M_WAITOK);
+ MAC_PERFORM(mount_init_label, label);
+ return (label);
+}
+
+void
+mac_mount_init(struct mount *mp)
+{
+
+ if (mac_labeled & MPC_OBJECT_MOUNT)
+ mp->mnt_label = mac_mount_label_alloc();
+ else
+ mp->mnt_label = NULL;
+}
+
+struct label *
+mac_vnode_label_alloc(void)
+{
+ struct label *label;
+
+ label = mac_labelzone_alloc(M_WAITOK);
+ MAC_PERFORM(vnode_init_label, label);
+ return (label);
+}
+
+void
+mac_vnode_init(struct vnode *vp)
+{
+
+ if (mac_labeled & MPC_OBJECT_VNODE)
+ vp->v_label = mac_vnode_label_alloc();
+ else
+ vp->v_label = NULL;
+}
+
+static void
+mac_devfs_label_free(struct label *label)
+{
+
+ MAC_PERFORM(devfs_destroy_label, label);
+ mac_labelzone_free(label);
+}
+
+void
+mac_devfs_destroy(struct devfs_dirent *de)
+{
+
+ if (de->de_label != NULL) {
+ mac_devfs_label_free(de->de_label);
+ de->de_label = NULL;
+ }
+}
+
+static void
+mac_mount_label_free(struct label *label)
+{
+
+ MAC_PERFORM(mount_destroy_label, label);
+ mac_labelzone_free(label);
+}
+
+void
+mac_mount_destroy(struct mount *mp)
+{
+
+ if (mp->mnt_label != NULL) {
+ mac_mount_label_free(mp->mnt_label);
+ mp->mnt_label = NULL;
+ }
+}
+
+void
+mac_vnode_label_free(struct label *label)
+{
+
+ MAC_PERFORM(vnode_destroy_label, label);
+ mac_labelzone_free(label);
+}
+
+void
+mac_vnode_destroy(struct vnode *vp)
+{
+
+ if (vp->v_label != NULL) {
+ mac_vnode_label_free(vp->v_label);
+ vp->v_label = NULL;
+ }
+}
+
+void
+mac_vnode_copy_label(struct label *src, struct label *dest)
+{
+
+ MAC_PERFORM(vnode_copy_label, src, dest);
+}
+
+int
+mac_vnode_externalize_label(struct label *label, char *elements,
+ char *outbuf, size_t outbuflen)
+{
+ int error;
+
+ MAC_EXTERNALIZE(vnode, label, elements, outbuf, outbuflen);
+
+ return (error);
+}
+
+int
+mac_vnode_internalize_label(struct label *label, char *string)
+{
+ int error;
+
+ MAC_INTERNALIZE(vnode, label, string);
+
+ return (error);
+}
+
+void
+mac_devfs_update(struct mount *mp, struct devfs_dirent *de, struct vnode *vp)
+{
+
+ MAC_PERFORM(devfs_update, mp, de, de->de_label, vp, vp->v_label);
+}
+
+void
+mac_devfs_vnode_associate(struct mount *mp, struct devfs_dirent *de,
+ struct vnode *vp)
+{
+
+ MAC_PERFORM(devfs_vnode_associate, mp, mp->mnt_label, de,
+ de->de_label, vp, vp->v_label);
+}
+
+int
+mac_vnode_associate_extattr(struct mount *mp, struct vnode *vp)
+{
+ int error;
+
+ ASSERT_VOP_LOCKED(vp, "mac_vnode_associate_extattr");
+
+ MAC_CHECK(vnode_associate_extattr, mp, mp->mnt_label, vp,
+ vp->v_label);
+
+ return (error);
+}
+
+void
+mac_vnode_associate_singlelabel(struct mount *mp, struct vnode *vp)
+{
+
+ MAC_PERFORM(vnode_associate_singlelabel, mp, mp->mnt_label, vp,
+ vp->v_label);
+}
+
+/*
+ * Functions implementing extended-attribute backed labels for file systems
+ * that support it.
+ *
+ * Where possible, we use EA transactions to make writes to multiple
+ * attributes across difference policies mutually atomic. We allow work to
+ * continue on file systems not supporting EA transactions, but generate a
+ * printf warning.
+ */
+int
+mac_vnode_create_extattr(struct ucred *cred, struct mount *mp,
+ struct vnode *dvp, struct vnode *vp, struct componentname *cnp)
+{
+ int error;
+
+ ASSERT_VOP_LOCKED(dvp, "mac_vnode_create_extattr");
+ ASSERT_VOP_LOCKED(vp, "mac_vnode_create_extattr");
+
+ error = VOP_OPENEXTATTR(vp, cred, curthread);
+ if (error == EOPNOTSUPP) {
+ if (ea_warn_once == 0) {
+ printf("Warning: transactions not supported "
+ "in EA write.\n");
+ ea_warn_once = 1;
+ }
+ } else if (error)
+ return (error);
+
+ MAC_CHECK(vnode_create_extattr, cred, mp, mp->mnt_label, dvp,
+ dvp->v_label, vp, vp->v_label, cnp);
+
+ if (error) {
+ VOP_CLOSEEXTATTR(vp, 0, NOCRED, curthread);
+ return (error);
+ }
+
+ error = VOP_CLOSEEXTATTR(vp, 1, NOCRED, curthread);
+ if (error == EOPNOTSUPP)
+ error = 0;
+
+ return (error);
+}
+
+static int
+mac_vnode_setlabel_extattr(struct ucred *cred, struct vnode *vp,
+ struct label *intlabel)
+{
+ int error;
+
+ ASSERT_VOP_LOCKED(vp, "mac_vnode_setlabel_extattr");
+
+ error = VOP_OPENEXTATTR(vp, cred, curthread);
+ if (error == EOPNOTSUPP) {
+ if (ea_warn_once == 0) {
+ printf("Warning: transactions not supported "
+ "in EA write.\n");
+ ea_warn_once = 1;
+ }
+ } else if (error)
+ return (error);
+
+ MAC_CHECK(vnode_setlabel_extattr, cred, vp, vp->v_label, intlabel);
+
+ if (error) {
+ VOP_CLOSEEXTATTR(vp, 0, NOCRED, curthread);
+ return (error);
+ }
+
+ error = VOP_CLOSEEXTATTR(vp, 1, NOCRED, curthread);
+ if (error == EOPNOTSUPP)
+ error = 0;
+
+ return (error);
+}
+
+void
+mac_vnode_execve_transition(struct ucred *old, struct ucred *new,
+ struct vnode *vp, struct label *interpvplabel, struct image_params *imgp)
+{
+
+ ASSERT_VOP_LOCKED(vp, "mac_vnode_execve_transition");
+
+ MAC_PERFORM(vnode_execve_transition, old, new, vp, vp->v_label,
+ interpvplabel, imgp, imgp->execlabel);
+}
+
+int
+mac_vnode_execve_will_transition(struct ucred *old, struct vnode *vp,
+ struct label *interpvplabel, struct image_params *imgp)
+{
+ int result;
+
+ ASSERT_VOP_LOCKED(vp, "mac_vnode_execve_will_transition");
+
+ result = 0;
+ MAC_BOOLEAN(vnode_execve_will_transition, ||, old, vp, vp->v_label,
+ interpvplabel, imgp, imgp->execlabel);
+
+ return (result);
+}
+
+int
+mac_vnode_check_access(struct ucred *cred, struct vnode *vp, accmode_t accmode)
+{
+ int error;
+
+ ASSERT_VOP_LOCKED(vp, "mac_vnode_check_access");
+
+ MAC_CHECK(vnode_check_access, cred, vp, vp->v_label, accmode);
+ return (error);
+}
+
+int
+mac_vnode_check_chdir(struct ucred *cred, struct vnode *dvp)
+{
+ int error;
+
+ ASSERT_VOP_LOCKED(dvp, "mac_vnode_check_chdir");
+
+ MAC_CHECK(vnode_check_chdir, cred, dvp, dvp->v_label);
+ return (error);
+}
+
+int
+mac_vnode_check_chroot(struct ucred *cred, struct vnode *dvp)
+{
+ int error;
+
+ ASSERT_VOP_LOCKED(dvp, "mac_vnode_check_chroot");
+
+ MAC_CHECK(vnode_check_chroot, cred, dvp, dvp->v_label);
+ return (error);
+}
+
+int
+mac_vnode_check_create(struct ucred *cred, struct vnode *dvp,
+ struct componentname *cnp, struct vattr *vap)
+{
+ int error;
+
+ ASSERT_VOP_LOCKED(dvp, "mac_vnode_check_create");
+
+ MAC_CHECK(vnode_check_create, cred, dvp, dvp->v_label, cnp, vap);
+ return (error);
+}
+
+int
+mac_vnode_check_deleteacl(struct ucred *cred, struct vnode *vp,
+ acl_type_t type)
+{
+ int error;
+
+ ASSERT_VOP_LOCKED(vp, "mac_vnode_check_deleteacl");
+
+ MAC_CHECK(vnode_check_deleteacl, cred, vp, vp->v_label, type);
+ return (error);
+}
+
+int
+mac_vnode_check_deleteextattr(struct ucred *cred, struct vnode *vp,
+ int attrnamespace, const char *name)
+{
+ int error;
+
+ ASSERT_VOP_LOCKED(vp, "mac_vnode_check_deleteextattr");
+
+ MAC_CHECK(vnode_check_deleteextattr, cred, vp, vp->v_label,
+ attrnamespace, name);
+ return (error);
+}
+
+int
+mac_vnode_check_exec(struct ucred *cred, struct vnode *vp,
+ struct image_params *imgp)
+{
+ int error;
+
+ ASSERT_VOP_LOCKED(vp, "mac_vnode_check_exec");
+
+ MAC_CHECK(vnode_check_exec, cred, vp, vp->v_label, imgp,
+ imgp->execlabel);
+
+ return (error);
+}
+
+int
+mac_vnode_check_getacl(struct ucred *cred, struct vnode *vp, acl_type_t type)
+{
+ int error;
+
+ ASSERT_VOP_LOCKED(vp, "mac_vnode_check_getacl");
+
+ MAC_CHECK(vnode_check_getacl, cred, vp, vp->v_label, type);
+ return (error);
+}
+
+int
+mac_vnode_check_getextattr(struct ucred *cred, struct vnode *vp,
+ int attrnamespace, const char *name, struct uio *uio)
+{
+ int error;
+
+ ASSERT_VOP_LOCKED(vp, "mac_vnode_check_getextattr");
+
+ MAC_CHECK(vnode_check_getextattr, cred, vp, vp->v_label,
+ attrnamespace, name, uio);
+ return (error);
+}
+
+int
+mac_vnode_check_link(struct ucred *cred, struct vnode *dvp,
+ struct vnode *vp, struct componentname *cnp)
+{
+ int error;
+
+ ASSERT_VOP_LOCKED(dvp, "mac_vnode_check_link");
+ ASSERT_VOP_LOCKED(vp, "mac_vnode_check_link");
+
+ MAC_CHECK(vnode_check_link, cred, dvp, dvp->v_label, vp,
+ vp->v_label, cnp);
+ return (error);
+}
+
+int
+mac_vnode_check_listextattr(struct ucred *cred, struct vnode *vp,
+ int attrnamespace)
+{
+ int error;
+
+ ASSERT_VOP_LOCKED(vp, "mac_vnode_check_listextattr");
+
+ MAC_CHECK(vnode_check_listextattr, cred, vp, vp->v_label,
+ attrnamespace);
+ return (error);
+}
+
+int
+mac_vnode_check_lookup(struct ucred *cred, struct vnode *dvp,
+ struct componentname *cnp)
+{
+ int error;
+
+ ASSERT_VOP_LOCKED(dvp, "mac_vnode_check_lookup");
+
+ MAC_CHECK(vnode_check_lookup, cred, dvp, dvp->v_label, cnp);
+ return (error);
+}
+
+int
+mac_vnode_check_mmap(struct ucred *cred, struct vnode *vp, int prot,
+ int flags)
+{
+ int error;
+
+ ASSERT_VOP_LOCKED(vp, "mac_vnode_check_mmap");
+
+ MAC_CHECK(vnode_check_mmap, cred, vp, vp->v_label, prot, flags);
+ return (error);
+}
+
+void
+mac_vnode_check_mmap_downgrade(struct ucred *cred, struct vnode *vp,
+ int *prot)
+{
+ int result = *prot;
+
+ ASSERT_VOP_LOCKED(vp, "mac_vnode_check_mmap_downgrade");
+
+ MAC_PERFORM(vnode_check_mmap_downgrade, cred, vp, vp->v_label,
+ &result);
+
+ *prot = result;
+}
+
+int
+mac_vnode_check_mprotect(struct ucred *cred, struct vnode *vp, int prot)
+{
+ int error;
+
+ ASSERT_VOP_LOCKED(vp, "mac_vnode_check_mprotect");
+
+ MAC_CHECK(vnode_check_mprotect, cred, vp, vp->v_label, prot);
+ return (error);
+}
+
+int
+mac_vnode_check_open(struct ucred *cred, struct vnode *vp, accmode_t accmode)
+{
+ int error;
+
+ ASSERT_VOP_LOCKED(vp, "mac_vnode_check_open");
+
+ MAC_CHECK(vnode_check_open, cred, vp, vp->v_label, accmode);
+ return (error);
+}
+
+int
+mac_vnode_check_poll(struct ucred *active_cred, struct ucred *file_cred,
+ struct vnode *vp)
+{
+ int error;
+
+ ASSERT_VOP_LOCKED(vp, "mac_vnode_check_poll");
+
+ MAC_CHECK(vnode_check_poll, active_cred, file_cred, vp,
+ vp->v_label);
+
+ return (error);
+}
+
+int
+mac_vnode_check_read(struct ucred *active_cred, struct ucred *file_cred,
+ struct vnode *vp)
+{
+ int error;
+
+ ASSERT_VOP_LOCKED(vp, "mac_vnode_check_read");
+
+ MAC_CHECK(vnode_check_read, active_cred, file_cred, vp,
+ vp->v_label);
+
+ return (error);
+}
+
+int
+mac_vnode_check_readdir(struct ucred *cred, struct vnode *dvp)
+{
+ int error;
+
+ ASSERT_VOP_LOCKED(dvp, "mac_vnode_check_readdir");
+
+ MAC_CHECK(vnode_check_readdir, cred, dvp, dvp->v_label);
+ return (error);
+}
+
+int
+mac_vnode_check_readlink(struct ucred *cred, struct vnode *vp)
+{
+ int error;
+
+ ASSERT_VOP_LOCKED(vp, "mac_vnode_check_readlink");
+
+ MAC_CHECK(vnode_check_readlink, cred, vp, vp->v_label);
+ return (error);
+}
+
+static int
+mac_vnode_check_relabel(struct ucred *cred, struct vnode *vp,
+ struct label *newlabel)
+{
+ int error;
+
+ ASSERT_VOP_LOCKED(vp, "mac_vnode_check_relabel");
+
+ MAC_CHECK(vnode_check_relabel, cred, vp, vp->v_label, newlabel);
+
+ return (error);
+}
+
+int
+mac_vnode_check_rename_from(struct ucred *cred, struct vnode *dvp,
+ struct vnode *vp, struct componentname *cnp)
+{
+ int error;
+
+ ASSERT_VOP_LOCKED(dvp, "mac_vnode_check_rename_from");
+ ASSERT_VOP_LOCKED(vp, "mac_vnode_check_rename_from");
+
+ MAC_CHECK(vnode_check_rename_from, cred, dvp, dvp->v_label, vp,
+ vp->v_label, cnp);
+ return (error);
+}
+
+int
+mac_vnode_check_rename_to(struct ucred *cred, struct vnode *dvp,
+ struct vnode *vp, int samedir, struct componentname *cnp)
+{
+ int error;
+
+ ASSERT_VOP_LOCKED(dvp, "mac_vnode_check_rename_to");
+ ASSERT_VOP_LOCKED(vp, "mac_vnode_check_rename_to");
+
+ MAC_CHECK(vnode_check_rename_to, cred, dvp, dvp->v_label, vp,
+ vp != NULL ? vp->v_label : NULL, samedir, cnp);
+ return (error);
+}
+
+int
+mac_vnode_check_revoke(struct ucred *cred, struct vnode *vp)
+{
+ int error;
+
+ ASSERT_VOP_LOCKED(vp, "mac_vnode_check_revoke");
+
+ MAC_CHECK(vnode_check_revoke, cred, vp, vp->v_label);
+ return (error);
+}
+
+int
+mac_vnode_check_setacl(struct ucred *cred, struct vnode *vp, acl_type_t type,
+ struct acl *acl)
+{
+ int error;
+
+ ASSERT_VOP_LOCKED(vp, "mac_vnode_check_setacl");
+
+ MAC_CHECK(vnode_check_setacl, cred, vp, vp->v_label, type, acl);
+ return (error);
+}
+
+int
+mac_vnode_check_setextattr(struct ucred *cred, struct vnode *vp,
+ int attrnamespace, const char *name, struct uio *uio)
+{
+ int error;
+
+ ASSERT_VOP_LOCKED(vp, "mac_vnode_check_setextattr");
+
+ MAC_CHECK(vnode_check_setextattr, cred, vp, vp->v_label,
+ attrnamespace, name, uio);
+ return (error);
+}
+
+int
+mac_vnode_check_setflags(struct ucred *cred, struct vnode *vp, u_long flags)
+{
+ int error;
+
+ ASSERT_VOP_LOCKED(vp, "mac_vnode_check_setflags");
+
+ MAC_CHECK(vnode_check_setflags, cred, vp, vp->v_label, flags);
+ return (error);
+}
+
+int
+mac_vnode_check_setmode(struct ucred *cred, struct vnode *vp, mode_t mode)
+{
+ int error;
+
+ ASSERT_VOP_LOCKED(vp, "mac_vnode_check_setmode");
+
+ MAC_CHECK(vnode_check_setmode, cred, vp, vp->v_label, mode);
+ return (error);
+}
+
+int
+mac_vnode_check_setowner(struct ucred *cred, struct vnode *vp, uid_t uid,
+ gid_t gid)
+{
+ int error;
+
+ ASSERT_VOP_LOCKED(vp, "mac_vnode_check_setowner");
+
+ MAC_CHECK(vnode_check_setowner, cred, vp, vp->v_label, uid, gid);
+ return (error);
+}
+
+int
+mac_vnode_check_setutimes(struct ucred *cred, struct vnode *vp,
+ struct timespec atime, struct timespec mtime)
+{
+ int error;
+
+ ASSERT_VOP_LOCKED(vp, "mac_vnode_check_setutimes");
+
+ MAC_CHECK(vnode_check_setutimes, cred, vp, vp->v_label, atime,
+ mtime);
+ return (error);
+}
+
+int
+mac_vnode_check_stat(struct ucred *active_cred, struct ucred *file_cred,
+ struct vnode *vp)
+{
+ int error;
+
+ ASSERT_VOP_LOCKED(vp, "mac_vnode_check_stat");
+
+ MAC_CHECK(vnode_check_stat, active_cred, file_cred, vp,
+ vp->v_label);
+ return (error);
+}
+
+int
+mac_vnode_check_unlink(struct ucred *cred, struct vnode *dvp,
+ struct vnode *vp, struct componentname *cnp)
+{
+ int error;
+
+ ASSERT_VOP_LOCKED(dvp, "mac_vnode_check_unlink");
+ ASSERT_VOP_LOCKED(vp, "mac_vnode_check_unlink");
+
+ MAC_CHECK(vnode_check_unlink, cred, dvp, dvp->v_label, vp,
+ vp->v_label, cnp);
+ return (error);
+}
+
+int
+mac_vnode_check_write(struct ucred *active_cred, struct ucred *file_cred,
+ struct vnode *vp)
+{
+ int error;
+
+ ASSERT_VOP_LOCKED(vp, "mac_vnode_check_write");
+
+ MAC_CHECK(vnode_check_write, active_cred, file_cred, vp,
+ vp->v_label);
+
+ return (error);
+}
+
+void
+mac_vnode_relabel(struct ucred *cred, struct vnode *vp,
+ struct label *newlabel)
+{
+
+ MAC_PERFORM(vnode_relabel, cred, vp, vp->v_label, newlabel);
+}
+
+void
+mac_mount_create(struct ucred *cred, struct mount *mp)
+{
+
+ MAC_PERFORM(mount_create, cred, mp, mp->mnt_label);
+}
+
+int
+mac_mount_check_stat(struct ucred *cred, struct mount *mount)
+{
+ int error;
+
+ MAC_CHECK(mount_check_stat, cred, mount, mount->mnt_label);
+
+ return (error);
+}
+
+void
+mac_devfs_create_device(struct ucred *cred, struct mount *mp,
+ struct cdev *dev, struct devfs_dirent *de)
+{
+
+ MAC_PERFORM(devfs_create_device, cred, mp, dev, de, de->de_label);
+}
+
+void
+mac_devfs_create_symlink(struct ucred *cred, struct mount *mp,
+ struct devfs_dirent *dd, struct devfs_dirent *de)
+{
+
+ MAC_PERFORM(devfs_create_symlink, cred, mp, dd, dd->de_label, de,
+ de->de_label);
+}
+
+void
+mac_devfs_create_directory(struct mount *mp, char *dirname, int dirnamelen,
+ struct devfs_dirent *de)
+{
+
+ MAC_PERFORM(devfs_create_directory, mp, dirname, dirnamelen, de,
+ de->de_label);
+}
+
+/*
+ * Implementation of VOP_SETLABEL() that relies on extended attributes to
+ * store label data. Can be referenced by filesystems supporting extended
+ * attributes.
+ */
+int
+vop_stdsetlabel_ea(struct vop_setlabel_args *ap)
+{
+ struct vnode *vp = ap->a_vp;
+ struct label *intlabel = ap->a_label;
+ int error;
+
+ ASSERT_VOP_LOCKED(vp, "vop_stdsetlabel_ea");
+
+ if ((vp->v_mount->mnt_flag & MNT_MULTILABEL) == 0)
+ return (EOPNOTSUPP);
+
+ error = mac_vnode_setlabel_extattr(ap->a_cred, vp, intlabel);
+ if (error)
+ return (error);
+
+ mac_vnode_relabel(ap->a_cred, vp, intlabel);
+
+ return (0);
+}
+
+int
+vn_setlabel(struct vnode *vp, struct label *intlabel, struct ucred *cred)
+{
+ int error;
+
+ if (vp->v_mount == NULL) {
+ /* printf("vn_setlabel: null v_mount\n"); */
+ if (vp->v_type != VNON)
+ printf("vn_setlabel: null v_mount with non-VNON\n");
+ return (EBADF);
+ }
+
+ if ((vp->v_mount->mnt_flag & MNT_MULTILABEL) == 0)
+ return (EOPNOTSUPP);
+
+ /*
+ * Multi-phase commit. First check the policies to confirm the
+ * change is OK. Then commit via the filesystem. Finally, update
+ * the actual vnode label.
+ *
+ * Question: maybe the filesystem should update the vnode at the end
+ * as part of VOP_SETLABEL()?
+ */
+ error = mac_vnode_check_relabel(cred, vp, intlabel);
+ if (error)
+ return (error);
+
+ /*
+ * VADMIN provides the opportunity for the filesystem to make
+ * decisions about who is and is not able to modify labels and
+ * protections on files. This might not be right. We can't assume
+ * VOP_SETLABEL() will do it, because we might implement that as part
+ * of vop_stdsetlabel_ea().
+ */
+ error = VOP_ACCESS(vp, VADMIN, cred, curthread);
+ if (error)
+ return (error);
+
+ error = VOP_SETLABEL(vp, intlabel, cred, curthread);
+ if (error)
+ return (error);
+
+ return (0);
+}
diff --git a/sys/security/mac_biba/mac_biba.c b/sys/security/mac_biba/mac_biba.c
new file mode 100644
index 0000000..4e10f27
--- /dev/null
+++ b/sys/security/mac_biba/mac_biba.c
@@ -0,0 +1,3569 @@
+/*-
+ * Copyright (c) 1999-2002, 2007-2008 Robert N. M. Watson
+ * Copyright (c) 2001-2005 McAfee, Inc.
+ * Copyright (c) 2006 SPARTA, Inc.
+ * All rights reserved.
+ *
+ * This software was developed by Robert Watson for the TrustedBSD Project.
+ *
+ * This software was developed for the FreeBSD Project in part by McAfee
+ * Research, the Security Research Division of McAfee, Inc. under
+ * DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA
+ * CHATS research program.
+ *
+ * This software was enhanced by SPARTA ISSO under SPAWAR contract
+ * N66001-04-C-6019 ("SEFOS").
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Developed by the TrustedBSD Project.
+ *
+ * Biba fixed label mandatory integrity policy.
+ */
+
+#include <sys/param.h>
+#include <sys/conf.h>
+#include <sys/extattr.h>
+#include <sys/kernel.h>
+#include <sys/ksem.h>
+#include <sys/malloc.h>
+#include <sys/mman.h>
+#include <sys/mount.h>
+#include <sys/priv.h>
+#include <sys/proc.h>
+#include <sys/sbuf.h>
+#include <sys/systm.h>
+#include <sys/sysproto.h>
+#include <sys/sysent.h>
+#include <sys/systm.h>
+#include <sys/vnode.h>
+#include <sys/file.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/pipe.h>
+#include <sys/sx.h>
+#include <sys/sysctl.h>
+#include <sys/msg.h>
+#include <sys/sem.h>
+#include <sys/shm.h>
+
+#include <fs/devfs/devfs.h>
+
+#include <net/bpfdesc.h>
+#include <net/if.h>
+#include <net/if_types.h>
+#include <net/if_var.h>
+
+#include <netinet/in.h>
+#include <netinet/in_pcb.h>
+#include <netinet/ip_var.h>
+
+#include <vm/uma.h>
+#include <vm/vm.h>
+
+#include <security/mac/mac_policy.h>
+#include <security/mac_biba/mac_biba.h>
+
+SYSCTL_DECL(_security_mac);
+
+SYSCTL_NODE(_security_mac, OID_AUTO, biba, CTLFLAG_RW, 0,
+ "TrustedBSD mac_biba policy controls");
+
+static int biba_label_size = sizeof(struct mac_biba);
+SYSCTL_INT(_security_mac_biba, OID_AUTO, label_size, CTLFLAG_RD,
+ &biba_label_size, 0, "Size of struct mac_biba");
+
+static int biba_enabled = 1;
+SYSCTL_INT(_security_mac_biba, OID_AUTO, enabled, CTLFLAG_RW, &biba_enabled,
+ 0, "Enforce MAC/Biba policy");
+TUNABLE_INT("security.mac.biba.enabled", &biba_enabled);
+
+static int destroyed_not_inited;
+SYSCTL_INT(_security_mac_biba, OID_AUTO, destroyed_not_inited, CTLFLAG_RD,
+ &destroyed_not_inited, 0, "Count of labels destroyed but not inited");
+
+static int trust_all_interfaces = 0;
+SYSCTL_INT(_security_mac_biba, OID_AUTO, trust_all_interfaces, CTLFLAG_RD,
+ &trust_all_interfaces, 0, "Consider all interfaces 'trusted' by MAC/Biba");
+TUNABLE_INT("security.mac.biba.trust_all_interfaces", &trust_all_interfaces);
+
+static char trusted_interfaces[128];
+SYSCTL_STRING(_security_mac_biba, OID_AUTO, trusted_interfaces, CTLFLAG_RD,
+ trusted_interfaces, 0, "Interfaces considered 'trusted' by MAC/Biba");
+TUNABLE_STR("security.mac.biba.trusted_interfaces", trusted_interfaces,
+ sizeof(trusted_interfaces));
+
+static int max_compartments = MAC_BIBA_MAX_COMPARTMENTS;
+SYSCTL_INT(_security_mac_biba, OID_AUTO, max_compartments, CTLFLAG_RD,
+ &max_compartments, 0, "Maximum supported compartments");
+
+static int ptys_equal = 0;
+SYSCTL_INT(_security_mac_biba, OID_AUTO, ptys_equal, CTLFLAG_RW, &ptys_equal,
+ 0, "Label pty devices as biba/equal on create");
+TUNABLE_INT("security.mac.biba.ptys_equal", &ptys_equal);
+
+static int interfaces_equal;
+SYSCTL_INT(_security_mac_biba, OID_AUTO, interfaces_equal, CTLFLAG_RW,
+ &interfaces_equal, 0, "Label network interfaces as biba/equal on create");
+TUNABLE_INT("security.mac.biba.interfaces_equal", &interfaces_equal);
+
+static int revocation_enabled = 0;
+SYSCTL_INT(_security_mac_biba, OID_AUTO, revocation_enabled, CTLFLAG_RW,
+ &revocation_enabled, 0, "Revoke access to objects on relabel");
+TUNABLE_INT("security.mac.biba.revocation_enabled", &revocation_enabled);
+
+static int biba_slot;
+#define SLOT(l) ((struct mac_biba *)mac_label_get((l), biba_slot))
+#define SLOT_SET(l, val) mac_label_set((l), biba_slot, (uintptr_t)(val))
+
+static uma_zone_t zone_biba;
+
+static __inline int
+biba_bit_set_empty(u_char *set) {
+ int i;
+
+ for (i = 0; i < MAC_BIBA_MAX_COMPARTMENTS >> 3; i++)
+ if (set[i] != 0)
+ return (0);
+ return (1);
+}
+
+static struct mac_biba *
+biba_alloc(int flag)
+{
+
+ return (uma_zalloc(zone_biba, flag | M_ZERO));
+}
+
+static void
+biba_free(struct mac_biba *mb)
+{
+
+ if (mb != NULL)
+ uma_zfree(zone_biba, mb);
+ else
+ atomic_add_int(&destroyed_not_inited, 1);
+}
+
+static int
+biba_atmostflags(struct mac_biba *mb, int flags)
+{
+
+ if ((mb->mb_flags & flags) != mb->mb_flags)
+ return (EINVAL);
+ return (0);
+}
+
+static int
+biba_dominate_element(struct mac_biba_element *a, struct mac_biba_element *b)
+{
+ int bit;
+
+ switch (a->mbe_type) {
+ case MAC_BIBA_TYPE_EQUAL:
+ case MAC_BIBA_TYPE_HIGH:
+ return (1);
+
+ case MAC_BIBA_TYPE_LOW:
+ switch (b->mbe_type) {
+ case MAC_BIBA_TYPE_GRADE:
+ case MAC_BIBA_TYPE_HIGH:
+ return (0);
+
+ case MAC_BIBA_TYPE_EQUAL:
+ case MAC_BIBA_TYPE_LOW:
+ return (1);
+
+ default:
+ panic("biba_dominate_element: b->mbe_type invalid");
+ }
+
+ case MAC_BIBA_TYPE_GRADE:
+ switch (b->mbe_type) {
+ case MAC_BIBA_TYPE_EQUAL:
+ case MAC_BIBA_TYPE_LOW:
+ return (1);
+
+ case MAC_BIBA_TYPE_HIGH:
+ return (0);
+
+ case MAC_BIBA_TYPE_GRADE:
+ for (bit = 1; bit <= MAC_BIBA_MAX_COMPARTMENTS; bit++)
+ if (!MAC_BIBA_BIT_TEST(bit,
+ a->mbe_compartments) &&
+ MAC_BIBA_BIT_TEST(bit, b->mbe_compartments))
+ return (0);
+ return (a->mbe_grade >= b->mbe_grade);
+
+ default:
+ panic("biba_dominate_element: b->mbe_type invalid");
+ }
+
+ default:
+ panic("biba_dominate_element: a->mbe_type invalid");
+ }
+
+ return (0);
+}
+
+static int
+biba_subject_dominate_high(struct mac_biba *mb)
+{
+ struct mac_biba_element *element;
+
+ KASSERT((mb->mb_flags & MAC_BIBA_FLAG_EFFECTIVE) != 0,
+ ("biba_effective_in_range: mb not effective"));
+ element = &mb->mb_effective;
+
+ return (element->mbe_type == MAC_BIBA_TYPE_EQUAL ||
+ element->mbe_type == MAC_BIBA_TYPE_HIGH);
+}
+
+static int
+biba_range_in_range(struct mac_biba *rangea, struct mac_biba *rangeb)
+{
+
+ return (biba_dominate_element(&rangeb->mb_rangehigh,
+ &rangea->mb_rangehigh) &&
+ biba_dominate_element(&rangea->mb_rangelow,
+ &rangeb->mb_rangelow));
+}
+
+static int
+biba_effective_in_range(struct mac_biba *effective, struct mac_biba *range)
+{
+
+ KASSERT((effective->mb_flags & MAC_BIBA_FLAG_EFFECTIVE) != 0,
+ ("biba_effective_in_range: a not effective"));
+ KASSERT((range->mb_flags & MAC_BIBA_FLAG_RANGE) != 0,
+ ("biba_effective_in_range: b not range"));
+
+ return (biba_dominate_element(&range->mb_rangehigh,
+ &effective->mb_effective) &&
+ biba_dominate_element(&effective->mb_effective,
+ &range->mb_rangelow));
+
+ return (1);
+}
+
+static int
+biba_dominate_effective(struct mac_biba *a, struct mac_biba *b)
+{
+ KASSERT((a->mb_flags & MAC_BIBA_FLAG_EFFECTIVE) != 0,
+ ("biba_dominate_effective: a not effective"));
+ KASSERT((b->mb_flags & MAC_BIBA_FLAG_EFFECTIVE) != 0,
+ ("biba_dominate_effective: b not effective"));
+
+ return (biba_dominate_element(&a->mb_effective, &b->mb_effective));
+}
+
+static int
+biba_equal_element(struct mac_biba_element *a, struct mac_biba_element *b)
+{
+
+ if (a->mbe_type == MAC_BIBA_TYPE_EQUAL ||
+ b->mbe_type == MAC_BIBA_TYPE_EQUAL)
+ return (1);
+
+ return (a->mbe_type == b->mbe_type && a->mbe_grade == b->mbe_grade);
+}
+
+static int
+biba_equal_effective(struct mac_biba *a, struct mac_biba *b)
+{
+
+ KASSERT((a->mb_flags & MAC_BIBA_FLAG_EFFECTIVE) != 0,
+ ("biba_equal_effective: a not effective"));
+ KASSERT((b->mb_flags & MAC_BIBA_FLAG_EFFECTIVE) != 0,
+ ("biba_equal_effective: b not effective"));
+
+ return (biba_equal_element(&a->mb_effective, &b->mb_effective));
+}
+
+static int
+biba_contains_equal(struct mac_biba *mb)
+{
+
+ if (mb->mb_flags & MAC_BIBA_FLAG_EFFECTIVE) {
+ if (mb->mb_effective.mbe_type == MAC_BIBA_TYPE_EQUAL)
+ return (1);
+ }
+
+ if (mb->mb_flags & MAC_BIBA_FLAG_RANGE) {
+ if (mb->mb_rangelow.mbe_type == MAC_BIBA_TYPE_EQUAL)
+ return (1);
+ if (mb->mb_rangehigh.mbe_type == MAC_BIBA_TYPE_EQUAL)
+ return (1);
+ }
+
+ return (0);
+}
+
+static int
+biba_subject_privileged(struct mac_biba *mb)
+{
+
+ KASSERT((mb->mb_flags & MAC_BIBA_FLAGS_BOTH) == MAC_BIBA_FLAGS_BOTH,
+ ("biba_subject_privileged: subject doesn't have both labels"));
+
+ /* If the effective is EQUAL, it's ok. */
+ if (mb->mb_effective.mbe_type == MAC_BIBA_TYPE_EQUAL)
+ return (0);
+
+ /* If either range endpoint is EQUAL, it's ok. */
+ if (mb->mb_rangelow.mbe_type == MAC_BIBA_TYPE_EQUAL ||
+ mb->mb_rangehigh.mbe_type == MAC_BIBA_TYPE_EQUAL)
+ return (0);
+
+ /* If the range is low-high, it's ok. */
+ if (mb->mb_rangelow.mbe_type == MAC_BIBA_TYPE_LOW &&
+ mb->mb_rangehigh.mbe_type == MAC_BIBA_TYPE_HIGH)
+ return (0);
+
+ /* It's not ok. */
+ return (EPERM);
+}
+
+static int
+biba_high_effective(struct mac_biba *mb)
+{
+
+ KASSERT((mb->mb_flags & MAC_BIBA_FLAG_EFFECTIVE) != 0,
+ ("biba_equal_effective: mb not effective"));
+
+ return (mb->mb_effective.mbe_type == MAC_BIBA_TYPE_HIGH);
+}
+
+static int
+biba_valid(struct mac_biba *mb)
+{
+
+ if (mb->mb_flags & MAC_BIBA_FLAG_EFFECTIVE) {
+ switch (mb->mb_effective.mbe_type) {
+ case MAC_BIBA_TYPE_GRADE:
+ break;
+
+ case MAC_BIBA_TYPE_EQUAL:
+ case MAC_BIBA_TYPE_HIGH:
+ case MAC_BIBA_TYPE_LOW:
+ if (mb->mb_effective.mbe_grade != 0 ||
+ !MAC_BIBA_BIT_SET_EMPTY(
+ mb->mb_effective.mbe_compartments))
+ return (EINVAL);
+ break;
+
+ default:
+ return (EINVAL);
+ }
+ } else {
+ if (mb->mb_effective.mbe_type != MAC_BIBA_TYPE_UNDEF)
+ return (EINVAL);
+ }
+
+ if (mb->mb_flags & MAC_BIBA_FLAG_RANGE) {
+ switch (mb->mb_rangelow.mbe_type) {
+ case MAC_BIBA_TYPE_GRADE:
+ break;
+
+ case MAC_BIBA_TYPE_EQUAL:
+ case MAC_BIBA_TYPE_HIGH:
+ case MAC_BIBA_TYPE_LOW:
+ if (mb->mb_rangelow.mbe_grade != 0 ||
+ !MAC_BIBA_BIT_SET_EMPTY(
+ mb->mb_rangelow.mbe_compartments))
+ return (EINVAL);
+ break;
+
+ default:
+ return (EINVAL);
+ }
+
+ switch (mb->mb_rangehigh.mbe_type) {
+ case MAC_BIBA_TYPE_GRADE:
+ break;
+
+ case MAC_BIBA_TYPE_EQUAL:
+ case MAC_BIBA_TYPE_HIGH:
+ case MAC_BIBA_TYPE_LOW:
+ if (mb->mb_rangehigh.mbe_grade != 0 ||
+ !MAC_BIBA_BIT_SET_EMPTY(
+ mb->mb_rangehigh.mbe_compartments))
+ return (EINVAL);
+ break;
+
+ default:
+ return (EINVAL);
+ }
+ if (!biba_dominate_element(&mb->mb_rangehigh,
+ &mb->mb_rangelow))
+ return (EINVAL);
+ } else {
+ if (mb->mb_rangelow.mbe_type != MAC_BIBA_TYPE_UNDEF ||
+ mb->mb_rangehigh.mbe_type != MAC_BIBA_TYPE_UNDEF)
+ return (EINVAL);
+ }
+
+ return (0);
+}
+
+static void
+biba_set_range(struct mac_biba *mb, u_short typelow, u_short gradelow,
+ u_char *compartmentslow, u_short typehigh, u_short gradehigh,
+ u_char *compartmentshigh)
+{
+
+ mb->mb_rangelow.mbe_type = typelow;
+ mb->mb_rangelow.mbe_grade = gradelow;
+ if (compartmentslow != NULL)
+ memcpy(mb->mb_rangelow.mbe_compartments, compartmentslow,
+ sizeof(mb->mb_rangelow.mbe_compartments));
+ mb->mb_rangehigh.mbe_type = typehigh;
+ mb->mb_rangehigh.mbe_grade = gradehigh;
+ if (compartmentshigh != NULL)
+ memcpy(mb->mb_rangehigh.mbe_compartments, compartmentshigh,
+ sizeof(mb->mb_rangehigh.mbe_compartments));
+ mb->mb_flags |= MAC_BIBA_FLAG_RANGE;
+}
+
+static void
+biba_set_effective(struct mac_biba *mb, u_short type, u_short grade,
+ u_char *compartments)
+{
+
+ mb->mb_effective.mbe_type = type;
+ mb->mb_effective.mbe_grade = grade;
+ if (compartments != NULL)
+ memcpy(mb->mb_effective.mbe_compartments, compartments,
+ sizeof(mb->mb_effective.mbe_compartments));
+ mb->mb_flags |= MAC_BIBA_FLAG_EFFECTIVE;
+}
+
+static void
+biba_copy_range(struct mac_biba *labelfrom, struct mac_biba *labelto)
+{
+
+ KASSERT((labelfrom->mb_flags & MAC_BIBA_FLAG_RANGE) != 0,
+ ("biba_copy_range: labelfrom not range"));
+
+ labelto->mb_rangelow = labelfrom->mb_rangelow;
+ labelto->mb_rangehigh = labelfrom->mb_rangehigh;
+ labelto->mb_flags |= MAC_BIBA_FLAG_RANGE;
+}
+
+static void
+biba_copy_effective(struct mac_biba *labelfrom, struct mac_biba *labelto)
+{
+
+ KASSERT((labelfrom->mb_flags & MAC_BIBA_FLAG_EFFECTIVE) != 0,
+ ("biba_copy_effective: labelfrom not effective"));
+
+ labelto->mb_effective = labelfrom->mb_effective;
+ labelto->mb_flags |= MAC_BIBA_FLAG_EFFECTIVE;
+}
+
+static void
+biba_copy(struct mac_biba *source, struct mac_biba *dest)
+{
+
+ if (source->mb_flags & MAC_BIBA_FLAG_EFFECTIVE)
+ biba_copy_effective(source, dest);
+ if (source->mb_flags & MAC_BIBA_FLAG_RANGE)
+ biba_copy_range(source, dest);
+}
+
+/*
+ * Policy module operations.
+ */
+static void
+biba_init(struct mac_policy_conf *conf)
+{
+
+ zone_biba = uma_zcreate("mac_biba", sizeof(struct mac_biba), NULL,
+ NULL, NULL, NULL, UMA_ALIGN_PTR, 0);
+}
+
+/*
+ * Label operations.
+ */
+static void
+biba_init_label(struct label *label)
+{
+
+ SLOT_SET(label, biba_alloc(M_WAITOK));
+}
+
+static int
+biba_init_label_waitcheck(struct label *label, int flag)
+{
+
+ SLOT_SET(label, biba_alloc(flag));
+ if (SLOT(label) == NULL)
+ return (ENOMEM);
+
+ return (0);
+}
+
+static void
+biba_destroy_label(struct label *label)
+{
+
+ biba_free(SLOT(label));
+ SLOT_SET(label, NULL);
+}
+
+/*
+ * biba_element_to_string() accepts an sbuf and Biba element. It converts
+ * the Biba element to a string and stores the result in the sbuf; if there
+ * isn't space in the sbuf, -1 is returned.
+ */
+static int
+biba_element_to_string(struct sbuf *sb, struct mac_biba_element *element)
+{
+ int i, first;
+
+ switch (element->mbe_type) {
+ case MAC_BIBA_TYPE_HIGH:
+ return (sbuf_printf(sb, "high"));
+
+ case MAC_BIBA_TYPE_LOW:
+ return (sbuf_printf(sb, "low"));
+
+ case MAC_BIBA_TYPE_EQUAL:
+ return (sbuf_printf(sb, "equal"));
+
+ case MAC_BIBA_TYPE_GRADE:
+ if (sbuf_printf(sb, "%d", element->mbe_grade) == -1)
+ return (-1);
+
+ first = 1;
+ for (i = 1; i <= MAC_BIBA_MAX_COMPARTMENTS; i++) {
+ if (MAC_BIBA_BIT_TEST(i, element->mbe_compartments)) {
+ if (first) {
+ if (sbuf_putc(sb, ':') == -1)
+ return (-1);
+ if (sbuf_printf(sb, "%d", i) == -1)
+ return (-1);
+ first = 0;
+ } else {
+ if (sbuf_printf(sb, "+%d", i) == -1)
+ return (-1);
+ }
+ }
+ }
+ return (0);
+
+ default:
+ panic("biba_element_to_string: invalid type (%d)",
+ element->mbe_type);
+ }
+}
+
+/*
+ * biba_to_string() converts a Biba label to a string, and places the results
+ * in the passed sbuf. It returns 0 on success, or EINVAL if there isn't
+ * room in the sbuf. Note: the sbuf will be modified even in a failure case,
+ * so the caller may need to revert the sbuf by restoring the offset if
+ * that's undesired.
+ */
+static int
+biba_to_string(struct sbuf *sb, struct mac_biba *mb)
+{
+
+ if (mb->mb_flags & MAC_BIBA_FLAG_EFFECTIVE) {
+ if (biba_element_to_string(sb, &mb->mb_effective) == -1)
+ return (EINVAL);
+ }
+
+ if (mb->mb_flags & MAC_BIBA_FLAG_RANGE) {
+ if (sbuf_putc(sb, '(') == -1)
+ return (EINVAL);
+
+ if (biba_element_to_string(sb, &mb->mb_rangelow) == -1)
+ return (EINVAL);
+
+ if (sbuf_putc(sb, '-') == -1)
+ return (EINVAL);
+
+ if (biba_element_to_string(sb, &mb->mb_rangehigh) == -1)
+ return (EINVAL);
+
+ if (sbuf_putc(sb, ')') == -1)
+ return (EINVAL);
+ }
+
+ return (0);
+}
+
+static int
+biba_externalize_label(struct label *label, char *element_name,
+ struct sbuf *sb, int *claimed)
+{
+ struct mac_biba *mb;
+
+ if (strcmp(MAC_BIBA_LABEL_NAME, element_name) != 0)
+ return (0);
+
+ (*claimed)++;
+
+ mb = SLOT(label);
+ return (biba_to_string(sb, mb));
+}
+
+static int
+biba_parse_element(struct mac_biba_element *element, char *string)
+{
+ char *compartment, *end, *grade;
+ int value;
+
+ if (strcmp(string, "high") == 0 || strcmp(string, "hi") == 0) {
+ element->mbe_type = MAC_BIBA_TYPE_HIGH;
+ element->mbe_grade = MAC_BIBA_TYPE_UNDEF;
+ } else if (strcmp(string, "low") == 0 || strcmp(string, "lo") == 0) {
+ element->mbe_type = MAC_BIBA_TYPE_LOW;
+ element->mbe_grade = MAC_BIBA_TYPE_UNDEF;
+ } else if (strcmp(string, "equal") == 0 ||
+ strcmp(string, "eq") == 0) {
+ element->mbe_type = MAC_BIBA_TYPE_EQUAL;
+ element->mbe_grade = MAC_BIBA_TYPE_UNDEF;
+ } else {
+ element->mbe_type = MAC_BIBA_TYPE_GRADE;
+
+ /*
+ * Numeric grade piece of the element.
+ */
+ grade = strsep(&string, ":");
+ value = strtol(grade, &end, 10);
+ if (end == grade || *end != '\0')
+ return (EINVAL);
+ if (value < 0 || value > 65535)
+ return (EINVAL);
+ element->mbe_grade = value;
+
+ /*
+ * Optional compartment piece of the element. If none are
+ * included, we assume that the label has no compartments.
+ */
+ if (string == NULL)
+ return (0);
+ if (*string == '\0')
+ return (0);
+
+ while ((compartment = strsep(&string, "+")) != NULL) {
+ value = strtol(compartment, &end, 10);
+ if (compartment == end || *end != '\0')
+ return (EINVAL);
+ if (value < 1 || value > MAC_BIBA_MAX_COMPARTMENTS)
+ return (EINVAL);
+ MAC_BIBA_BIT_SET(value, element->mbe_compartments);
+ }
+ }
+
+ return (0);
+}
+
+/*
+ * Note: destructively consumes the string, make a local copy before calling
+ * if that's a problem.
+ */
+static int
+biba_parse(struct mac_biba *mb, char *string)
+{
+ char *rangehigh, *rangelow, *effective;
+ int error;
+
+ effective = strsep(&string, "(");
+ if (*effective == '\0')
+ effective = NULL;
+
+ if (string != NULL) {
+ rangelow = strsep(&string, "-");
+ if (string == NULL)
+ return (EINVAL);
+ rangehigh = strsep(&string, ")");
+ if (string == NULL)
+ return (EINVAL);
+ if (*string != '\0')
+ return (EINVAL);
+ } else {
+ rangelow = NULL;
+ rangehigh = NULL;
+ }
+
+ KASSERT((rangelow != NULL && rangehigh != NULL) ||
+ (rangelow == NULL && rangehigh == NULL),
+ ("biba_parse: range mismatch"));
+
+ bzero(mb, sizeof(*mb));
+ if (effective != NULL) {
+ error = biba_parse_element(&mb->mb_effective, effective);
+ if (error)
+ return (error);
+ mb->mb_flags |= MAC_BIBA_FLAG_EFFECTIVE;
+ }
+
+ if (rangelow != NULL) {
+ error = biba_parse_element(&mb->mb_rangelow, rangelow);
+ if (error)
+ return (error);
+ error = biba_parse_element(&mb->mb_rangehigh, rangehigh);
+ if (error)
+ return (error);
+ mb->mb_flags |= MAC_BIBA_FLAG_RANGE;
+ }
+
+ error = biba_valid(mb);
+ if (error)
+ return (error);
+
+ return (0);
+}
+
+static int
+biba_internalize_label(struct label *label, char *element_name,
+ char *element_data, int *claimed)
+{
+ struct mac_biba *mb, mb_temp;
+ int error;
+
+ if (strcmp(MAC_BIBA_LABEL_NAME, element_name) != 0)
+ return (0);
+
+ (*claimed)++;
+
+ error = biba_parse(&mb_temp, element_data);
+ if (error)
+ return (error);
+
+ mb = SLOT(label);
+ *mb = mb_temp;
+
+ return (0);
+}
+
+static void
+biba_copy_label(struct label *src, struct label *dest)
+{
+
+ *SLOT(dest) = *SLOT(src);
+}
+
+/*
+ * Object-specific entry point implementations are sorted alphabetically by
+ * object type name and then by operation.
+ */
+static int
+biba_bpfdesc_check_receive(struct bpf_d *d, struct label *dlabel,
+ struct ifnet *ifp, struct label *ifplabel)
+{
+ struct mac_biba *a, *b;
+
+ if (!biba_enabled)
+ return (0);
+
+ a = SLOT(dlabel);
+ b = SLOT(ifplabel);
+
+ if (biba_equal_effective(a, b))
+ return (0);
+ return (EACCES);
+}
+
+static void
+biba_bpfdesc_create(struct ucred *cred, struct bpf_d *d,
+ struct label *dlabel)
+{
+ struct mac_biba *source, *dest;
+
+ source = SLOT(cred->cr_label);
+ dest = SLOT(dlabel);
+
+ biba_copy_effective(source, dest);
+}
+
+static void
+biba_bpfdesc_create_mbuf(struct bpf_d *d, struct label *dlabel,
+ struct mbuf *m, struct label *mlabel)
+{
+ struct mac_biba *source, *dest;
+
+ source = SLOT(dlabel);
+ dest = SLOT(mlabel);
+
+ biba_copy_effective(source, dest);
+}
+
+static void
+biba_cred_associate_nfsd(struct ucred *cred)
+{
+ struct mac_biba *label;
+
+ label = SLOT(cred->cr_label);
+ biba_set_effective(label, MAC_BIBA_TYPE_LOW, 0, NULL);
+ biba_set_range(label, MAC_BIBA_TYPE_LOW, 0, NULL, MAC_BIBA_TYPE_HIGH,
+ 0, NULL);
+}
+
+static int
+biba_cred_check_relabel(struct ucred *cred, struct label *newlabel)
+{
+ struct mac_biba *subj, *new;
+ int error;
+
+ subj = SLOT(cred->cr_label);
+ new = SLOT(newlabel);
+
+ /*
+ * If there is a Biba label update for the credential, it may
+ * be an update of the effective, range, or both.
+ */
+ error = biba_atmostflags(new, MAC_BIBA_FLAGS_BOTH);
+ if (error)
+ return (error);
+
+ /*
+ * If the Biba label is to be changed, authorize as appropriate.
+ */
+ if (new->mb_flags & MAC_BIBA_FLAGS_BOTH) {
+ /*
+ * If the change request modifies both the Biba label
+ * effective and range, check that the new effective will be
+ * in the new range.
+ */
+ if ((new->mb_flags & MAC_BIBA_FLAGS_BOTH) ==
+ MAC_BIBA_FLAGS_BOTH &&
+ !biba_effective_in_range(new, new))
+ return (EINVAL);
+
+ /*
+ * To change the Biba effective label on a credential, the
+ * new effective label must be in the current range.
+ */
+ if (new->mb_flags & MAC_BIBA_FLAG_EFFECTIVE &&
+ !biba_effective_in_range(new, subj))
+ return (EPERM);
+
+ /*
+ * To change the Biba range on a credential, the new range
+ * label must be in the current range.
+ */
+ if (new->mb_flags & MAC_BIBA_FLAG_RANGE &&
+ !biba_range_in_range(new, subj))
+ return (EPERM);
+
+ /*
+ * To have EQUAL in any component of the new credential Biba
+ * label, the subject must already have EQUAL in their label.
+ */
+ if (biba_contains_equal(new)) {
+ error = biba_subject_privileged(subj);
+ if (error)
+ return (error);
+ }
+ }
+
+ return (0);
+}
+
+static int
+biba_cred_check_visible(struct ucred *u1, struct ucred *u2)
+{
+ struct mac_biba *subj, *obj;
+
+ if (!biba_enabled)
+ return (0);
+
+ subj = SLOT(u1->cr_label);
+ obj = SLOT(u2->cr_label);
+
+ /* XXX: range */
+ if (!biba_dominate_effective(obj, subj))
+ return (ESRCH);
+
+ return (0);
+}
+
+static void
+biba_cred_create_init(struct ucred *cred)
+{
+ struct mac_biba *dest;
+
+ dest = SLOT(cred->cr_label);
+
+ biba_set_effective(dest, MAC_BIBA_TYPE_HIGH, 0, NULL);
+ biba_set_range(dest, MAC_BIBA_TYPE_LOW, 0, NULL, MAC_BIBA_TYPE_HIGH,
+ 0, NULL);
+}
+
+static void
+biba_cred_create_swapper(struct ucred *cred)
+{
+ struct mac_biba *dest;
+
+ dest = SLOT(cred->cr_label);
+
+ biba_set_effective(dest, MAC_BIBA_TYPE_EQUAL, 0, NULL);
+ biba_set_range(dest, MAC_BIBA_TYPE_LOW, 0, NULL, MAC_BIBA_TYPE_HIGH,
+ 0, NULL);
+}
+
+static void
+biba_cred_relabel(struct ucred *cred, struct label *newlabel)
+{
+ struct mac_biba *source, *dest;
+
+ source = SLOT(newlabel);
+ dest = SLOT(cred->cr_label);
+
+ biba_copy(source, dest);
+}
+
+static void
+biba_devfs_create_device(struct ucred *cred, struct mount *mp,
+ struct cdev *dev, struct devfs_dirent *de, struct label *delabel)
+{
+ struct mac_biba *mb;
+ int biba_type;
+
+ mb = SLOT(delabel);
+ if (strcmp(dev->si_name, "null") == 0 ||
+ strcmp(dev->si_name, "zero") == 0 ||
+ strcmp(dev->si_name, "random") == 0 ||
+ strncmp(dev->si_name, "fd/", strlen("fd/")) == 0)
+ biba_type = MAC_BIBA_TYPE_EQUAL;
+ else if (ptys_equal &&
+ (strncmp(dev->si_name, "ttyp", strlen("ttyp")) == 0 ||
+ strncmp(dev->si_name, "ptyp", strlen("ptyp")) == 0))
+ biba_type = MAC_BIBA_TYPE_EQUAL;
+ else
+ biba_type = MAC_BIBA_TYPE_HIGH;
+ biba_set_effective(mb, biba_type, 0, NULL);
+}
+
+static void
+biba_devfs_create_directory(struct mount *mp, char *dirname, int dirnamelen,
+ struct devfs_dirent *de, struct label *delabel)
+{
+ struct mac_biba *mb;
+
+ mb = SLOT(delabel);
+
+ biba_set_effective(mb, MAC_BIBA_TYPE_HIGH, 0, NULL);
+}
+
+static void
+biba_devfs_create_symlink(struct ucred *cred, struct mount *mp,
+ struct devfs_dirent *dd, struct label *ddlabel, struct devfs_dirent *de,
+ struct label *delabel)
+{
+ struct mac_biba *source, *dest;
+
+ source = SLOT(cred->cr_label);
+ dest = SLOT(delabel);
+
+ biba_copy_effective(source, dest);
+}
+
+static void
+biba_devfs_update(struct mount *mp, struct devfs_dirent *de,
+ struct label *delabel, struct vnode *vp, struct label *vplabel)
+{
+ struct mac_biba *source, *dest;
+
+ source = SLOT(vplabel);
+ dest = SLOT(delabel);
+
+ biba_copy(source, dest);
+}
+
+static void
+biba_devfs_vnode_associate(struct mount *mp, struct label *mntlabel,
+ struct devfs_dirent *de, struct label *delabel, struct vnode *vp,
+ struct label *vplabel)
+{
+ struct mac_biba *source, *dest;
+
+ source = SLOT(delabel);
+ dest = SLOT(vplabel);
+
+ biba_copy_effective(source, dest);
+}
+
+static int
+biba_ifnet_check_relabel(struct ucred *cred, struct ifnet *ifp,
+ struct label *ifplabel, struct label *newlabel)
+{
+ struct mac_biba *subj, *new;
+ int error;
+
+ subj = SLOT(cred->cr_label);
+ new = SLOT(newlabel);
+
+ /*
+ * If there is a Biba label update for the interface, it may be an
+ * update of the effective, range, or both.
+ */
+ error = biba_atmostflags(new, MAC_BIBA_FLAGS_BOTH);
+ if (error)
+ return (error);
+
+ /*
+ * Relabling network interfaces requires Biba privilege.
+ */
+ error = biba_subject_privileged(subj);
+ if (error)
+ return (error);
+
+ return (0);
+}
+
+static int
+biba_ifnet_check_transmit(struct ifnet *ifp, struct label *ifplabel,
+ struct mbuf *m, struct label *mlabel)
+{
+ struct mac_biba *p, *i;
+
+ if (!biba_enabled)
+ return (0);
+
+ p = SLOT(mlabel);
+ i = SLOT(ifplabel);
+
+ return (biba_effective_in_range(p, i) ? 0 : EACCES);
+}
+
+static void
+biba_ifnet_create(struct ifnet *ifp, struct label *ifplabel)
+{
+ char tifname[IFNAMSIZ], *p, *q;
+ char tiflist[sizeof(trusted_interfaces)];
+ struct mac_biba *dest;
+ int len, type;
+
+ dest = SLOT(ifplabel);
+
+ if (ifp->if_type == IFT_LOOP || interfaces_equal != 0) {
+ type = MAC_BIBA_TYPE_EQUAL;
+ goto set;
+ }
+
+ if (trust_all_interfaces) {
+ type = MAC_BIBA_TYPE_HIGH;
+ goto set;
+ }
+
+ type = MAC_BIBA_TYPE_LOW;
+
+ if (trusted_interfaces[0] == '\0' ||
+ !strvalid(trusted_interfaces, sizeof(trusted_interfaces)))
+ goto set;
+
+ bzero(tiflist, sizeof(tiflist));
+ for (p = trusted_interfaces, q = tiflist; *p != '\0'; p++, q++)
+ if(*p != ' ' && *p != '\t')
+ *q = *p;
+
+ for (p = q = tiflist;; p++) {
+ if (*p == ',' || *p == '\0') {
+ len = p - q;
+ if (len < IFNAMSIZ) {
+ bzero(tifname, sizeof(tifname));
+ bcopy(q, tifname, len);
+ if (strcmp(tifname, ifp->if_xname) == 0) {
+ type = MAC_BIBA_TYPE_HIGH;
+ break;
+ }
+ } else {
+ *p = '\0';
+ printf("mac_biba warning: interface name "
+ "\"%s\" is too long (must be < %d)\n",
+ q, IFNAMSIZ);
+ }
+ if (*p == '\0')
+ break;
+ q = p + 1;
+ }
+ }
+set:
+ biba_set_effective(dest, type, 0, NULL);
+ biba_set_range(dest, type, 0, NULL, type, 0, NULL);
+}
+
+static void
+biba_ifnet_create_mbuf(struct ifnet *ifp, struct label *ifplabel,
+ struct mbuf *m, struct label *mlabel)
+{
+ struct mac_biba *source, *dest;
+
+ source = SLOT(ifplabel);
+ dest = SLOT(mlabel);
+
+ biba_copy_effective(source, dest);
+}
+
+static void
+biba_ifnet_relabel(struct ucred *cred, struct ifnet *ifp,
+ struct label *ifplabel, struct label *newlabel)
+{
+ struct mac_biba *source, *dest;
+
+ source = SLOT(newlabel);
+ dest = SLOT(ifplabel);
+
+ biba_copy(source, dest);
+}
+
+static int
+biba_inpcb_check_deliver(struct inpcb *inp, struct label *inplabel,
+ struct mbuf *m, struct label *mlabel)
+{
+ struct mac_biba *p, *i;
+
+ if (!biba_enabled)
+ return (0);
+
+ p = SLOT(mlabel);
+ i = SLOT(inplabel);
+
+ return (biba_equal_effective(p, i) ? 0 : EACCES);
+}
+
+static int
+biba_inpcb_check_visible(struct ucred *cred, struct inpcb *inp,
+ struct label *inplabel)
+{
+ struct mac_biba *subj, *obj;
+
+ if (!biba_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(inplabel);
+
+ if (!biba_dominate_effective(obj, subj))
+ return (ENOENT);
+
+ return (0);
+}
+
+static void
+biba_inpcb_create(struct socket *so, struct label *solabel,
+ struct inpcb *inp, struct label *inplabel)
+{
+ struct mac_biba *source, *dest;
+
+ source = SLOT(solabel);
+ dest = SLOT(inplabel);
+
+ biba_copy_effective(source, dest);
+}
+
+static void
+biba_inpcb_create_mbuf(struct inpcb *inp, struct label *inplabel,
+ struct mbuf *m, struct label *mlabel)
+{
+ struct mac_biba *source, *dest;
+
+ source = SLOT(inplabel);
+ dest = SLOT(mlabel);
+
+ biba_copy_effective(source, dest);
+}
+
+static void
+biba_inpcb_sosetlabel(struct socket *so, struct label *solabel,
+ struct inpcb *inp, struct label *inplabel)
+{
+ struct mac_biba *source, *dest;
+
+ source = SLOT(solabel);
+ dest = SLOT(inplabel);
+
+ biba_copy(source, dest);
+}
+
+static void
+biba_ip6q_create(struct mbuf *m, struct label *mlabel, struct ip6q *q6,
+ struct label *q6label)
+{
+ struct mac_biba *source, *dest;
+
+ source = SLOT(mlabel);
+ dest = SLOT(q6label);
+
+ biba_copy_effective(source, dest);
+}
+
+static int
+biba_ip6q_match(struct mbuf *m, struct label *mlabel, struct ip6q *q6,
+ struct label *q6label)
+{
+ struct mac_biba *a, *b;
+
+ a = SLOT(q6label);
+ b = SLOT(mlabel);
+
+ return (biba_equal_effective(a, b));
+}
+
+static void
+biba_ip6q_reassemble(struct ip6q *q6, struct label *q6label, struct mbuf *m,
+ struct label *mlabel)
+{
+ struct mac_biba *source, *dest;
+
+ source = SLOT(q6label);
+ dest = SLOT(mlabel);
+
+ /* Just use the head, since we require them all to match. */
+ biba_copy_effective(source, dest);
+}
+
+static void
+biba_ip6q_update(struct mbuf *m, struct label *mlabel, struct ip6q *q6,
+ struct label *q6label)
+{
+
+ /* NOOP: we only accept matching labels, so no need to update */
+}
+
+static void
+biba_ipq_create(struct mbuf *m, struct label *mlabel, struct ipq *q,
+ struct label *qlabel)
+{
+ struct mac_biba *source, *dest;
+
+ source = SLOT(mlabel);
+ dest = SLOT(qlabel);
+
+ biba_copy_effective(source, dest);
+}
+
+static int
+biba_ipq_match(struct mbuf *m, struct label *mlabel, struct ipq *q,
+ struct label *qlabel)
+{
+ struct mac_biba *a, *b;
+
+ a = SLOT(qlabel);
+ b = SLOT(mlabel);
+
+ return (biba_equal_effective(a, b));
+}
+
+static void
+biba_ipq_reassemble(struct ipq *q, struct label *qlabel, struct mbuf *m,
+ struct label *mlabel)
+{
+ struct mac_biba *source, *dest;
+
+ source = SLOT(qlabel);
+ dest = SLOT(mlabel);
+
+ /* Just use the head, since we require them all to match. */
+ biba_copy_effective(source, dest);
+}
+
+static void
+biba_ipq_update(struct mbuf *m, struct label *mlabel, struct ipq *q,
+ struct label *qlabel)
+{
+
+ /* NOOP: we only accept matching labels, so no need to update */
+}
+
+static int
+biba_kld_check_load(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel)
+{
+ struct mac_biba *subj, *obj;
+ int error;
+
+ if (!biba_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+
+ error = biba_subject_privileged(subj);
+ if (error)
+ return (error);
+
+ obj = SLOT(vplabel);
+ if (!biba_high_effective(obj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+biba_mount_check_stat(struct ucred *cred, struct mount *mp,
+ struct label *mplabel)
+{
+ struct mac_biba *subj, *obj;
+
+ if (!biba_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(mplabel);
+
+ if (!biba_dominate_effective(obj, subj))
+ return (EACCES);
+
+ return (0);
+}
+
+static void
+biba_mount_create(struct ucred *cred, struct mount *mp,
+ struct label *mplabel)
+{
+ struct mac_biba *source, *dest;
+
+ source = SLOT(cred->cr_label);
+ dest = SLOT(mplabel);
+
+ biba_copy_effective(source, dest);
+}
+
+static void
+biba_netatalk_aarp_send(struct ifnet *ifp, struct label *ifplabel,
+ struct mbuf *m, struct label *mlabel)
+{
+ struct mac_biba *dest;
+
+ dest = SLOT(mlabel);
+
+ biba_set_effective(dest, MAC_BIBA_TYPE_EQUAL, 0, NULL);
+}
+
+static void
+biba_netinet_arp_send(struct ifnet *ifp, struct label *ifplabel,
+ struct mbuf *m, struct label *mlabel)
+{
+ struct mac_biba *dest;
+
+ dest = SLOT(mlabel);
+
+ biba_set_effective(dest, MAC_BIBA_TYPE_EQUAL, 0, NULL);
+}
+
+static void
+biba_netinet_firewall_reply(struct mbuf *mrecv, struct label *mrecvlabel,
+ struct mbuf *msend, struct label *msendlabel)
+{
+ struct mac_biba *source, *dest;
+
+ source = SLOT(mrecvlabel);
+ dest = SLOT(msendlabel);
+
+ biba_copy_effective(source, dest);
+}
+
+static void
+biba_netinet_firewall_send(struct mbuf *m, struct label *mlabel)
+{
+ struct mac_biba *dest;
+
+ dest = SLOT(mlabel);
+
+ /* XXX: where is the label for the firewall really coming from? */
+ biba_set_effective(dest, MAC_BIBA_TYPE_EQUAL, 0, NULL);
+}
+
+static void
+biba_netinet_fragment(struct mbuf *m, struct label *mlabel,
+ struct mbuf *frag, struct label *fraglabel)
+{
+ struct mac_biba *source, *dest;
+
+ source = SLOT(mlabel);
+ dest = SLOT(fraglabel);
+
+ biba_copy_effective(source, dest);
+}
+
+static void
+biba_netinet_icmp_reply(struct mbuf *mrecv, struct label *mrecvlabel,
+ struct mbuf *msend, struct label *msendlabel)
+{
+ struct mac_biba *source, *dest;
+
+ source = SLOT(mrecvlabel);
+ dest = SLOT(msendlabel);
+
+ biba_copy_effective(source, dest);
+}
+
+static void
+biba_netinet_igmp_send(struct ifnet *ifp, struct label *ifplabel,
+ struct mbuf *m, struct label *mlabel)
+{
+ struct mac_biba *dest;
+
+ dest = SLOT(mlabel);
+
+ biba_set_effective(dest, MAC_BIBA_TYPE_EQUAL, 0, NULL);
+}
+
+static void
+biba_netinet6_nd6_send(struct ifnet *ifp, struct label *ifplabel,
+ struct mbuf *m, struct label *mlabel)
+{
+ struct mac_biba *dest;
+
+ dest = SLOT(mlabel);
+
+ biba_set_effective(dest, MAC_BIBA_TYPE_EQUAL, 0, NULL);
+}
+
+static int
+biba_pipe_check_ioctl(struct ucred *cred, struct pipepair *pp,
+ struct label *pplabel, unsigned long cmd, void /* caddr_t */ *data)
+{
+
+ if(!biba_enabled)
+ return (0);
+
+ /* XXX: This will be implemented soon... */
+
+ return (0);
+}
+
+static int
+biba_pipe_check_poll(struct ucred *cred, struct pipepair *pp,
+ struct label *pplabel)
+{
+ struct mac_biba *subj, *obj;
+
+ if (!biba_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(pplabel);
+
+ if (!biba_dominate_effective(obj, subj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+biba_pipe_check_read(struct ucred *cred, struct pipepair *pp,
+ struct label *pplabel)
+{
+ struct mac_biba *subj, *obj;
+
+ if (!biba_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(pplabel);
+
+ if (!biba_dominate_effective(obj, subj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+biba_pipe_check_relabel(struct ucred *cred, struct pipepair *pp,
+ struct label *pplabel, struct label *newlabel)
+{
+ struct mac_biba *subj, *obj, *new;
+ int error;
+
+ new = SLOT(newlabel);
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(pplabel);
+
+ /*
+ * If there is a Biba label update for a pipe, it must be a effective
+ * update.
+ */
+ error = biba_atmostflags(new, MAC_BIBA_FLAG_EFFECTIVE);
+ if (error)
+ return (error);
+
+ /*
+ * To perform a relabel of a pipe (Biba label or not), Biba must
+ * authorize the relabel.
+ */
+ if (!biba_effective_in_range(obj, subj))
+ return (EPERM);
+
+ /*
+ * If the Biba label is to be changed, authorize as appropriate.
+ */
+ if (new->mb_flags & MAC_BIBA_FLAG_EFFECTIVE) {
+ /*
+ * To change the Biba label on a pipe, the new pipe label
+ * must be in the subject range.
+ */
+ if (!biba_effective_in_range(new, subj))
+ return (EPERM);
+
+ /*
+ * To change the Biba label on a pipe to be EQUAL, the
+ * subject must have appropriate privilege.
+ */
+ if (biba_contains_equal(new)) {
+ error = biba_subject_privileged(subj);
+ if (error)
+ return (error);
+ }
+ }
+
+ return (0);
+}
+
+static int
+biba_pipe_check_stat(struct ucred *cred, struct pipepair *pp,
+ struct label *pplabel)
+{
+ struct mac_biba *subj, *obj;
+
+ if (!biba_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(pplabel);
+
+ if (!biba_dominate_effective(obj, subj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+biba_pipe_check_write(struct ucred *cred, struct pipepair *pp,
+ struct label *pplabel)
+{
+ struct mac_biba *subj, *obj;
+
+ if (!biba_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(pplabel);
+
+ if (!biba_dominate_effective(subj, obj))
+ return (EACCES);
+
+ return (0);
+}
+
+static void
+biba_pipe_create(struct ucred *cred, struct pipepair *pp,
+ struct label *pplabel)
+{
+ struct mac_biba *source, *dest;
+
+ source = SLOT(cred->cr_label);
+ dest = SLOT(pplabel);
+
+ biba_copy_effective(source, dest);
+}
+
+static void
+biba_pipe_relabel(struct ucred *cred, struct pipepair *pp,
+ struct label *pplabel, struct label *newlabel)
+{
+ struct mac_biba *source, *dest;
+
+ source = SLOT(newlabel);
+ dest = SLOT(pplabel);
+
+ biba_copy(source, dest);
+}
+
+static int
+biba_posixsem_check_openunlink(struct ucred *cred, struct ksem *ks,
+ struct label *kslabel)
+{
+ struct mac_biba *subj, *obj;
+
+ if (!biba_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(kslabel);
+
+ if (!biba_dominate_effective(subj, obj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+biba_posixsem_check_write(struct ucred *active_cred, struct ucred *file_cred,
+ struct ksem *ks, struct label *kslabel)
+{
+ struct mac_biba *subj, *obj;
+
+ if (!biba_enabled)
+ return (0);
+
+ subj = SLOT(active_cred->cr_label);
+ obj = SLOT(kslabel);
+
+ if (!biba_dominate_effective(subj, obj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+biba_posixsem_check_rdonly(struct ucred *active_cred, struct ucred *file_cred,
+ struct ksem *ks, struct label *kslabel)
+{
+ struct mac_biba *subj, *obj;
+
+ if (!biba_enabled)
+ return (0);
+
+ subj = SLOT(active_cred->cr_label);
+ obj = SLOT(kslabel);
+
+ if (!biba_dominate_effective(obj, subj))
+ return (EACCES);
+
+ return (0);
+}
+
+static void
+biba_posixsem_create(struct ucred *cred, struct ksem *ks,
+ struct label *kslabel)
+{
+ struct mac_biba *source, *dest;
+
+ source = SLOT(cred->cr_label);
+ dest = SLOT(kslabel);
+
+ biba_copy_effective(source, dest);
+}
+
+/*
+ * Some system privileges are allowed regardless of integrity grade; others
+ * are allowed only when running with privilege with respect to the Biba
+ * policy as they might otherwise allow bypassing of the integrity policy.
+ */
+static int
+biba_priv_check(struct ucred *cred, int priv)
+{
+ struct mac_biba *subj;
+ int error;
+
+ if (!biba_enabled)
+ return (0);
+
+ /*
+ * Exempt only specific privileges from the Biba integrity policy.
+ */
+ switch (priv) {
+ case PRIV_KTRACE:
+ case PRIV_MSGBUF:
+
+ /*
+ * Allow processes to manipulate basic process audit properties, and
+ * to submit audit records.
+ */
+ case PRIV_AUDIT_GETAUDIT:
+ case PRIV_AUDIT_SETAUDIT:
+ case PRIV_AUDIT_SUBMIT:
+
+ /*
+ * Allow processes to manipulate their regular UNIX credentials.
+ */
+ case PRIV_CRED_SETUID:
+ case PRIV_CRED_SETEUID:
+ case PRIV_CRED_SETGID:
+ case PRIV_CRED_SETEGID:
+ case PRIV_CRED_SETGROUPS:
+ case PRIV_CRED_SETREUID:
+ case PRIV_CRED_SETREGID:
+ case PRIV_CRED_SETRESUID:
+ case PRIV_CRED_SETRESGID:
+
+ /*
+ * Allow processes to perform system monitoring.
+ */
+ case PRIV_SEEOTHERGIDS:
+ case PRIV_SEEOTHERUIDS:
+ break;
+
+ /*
+ * Allow access to general process debugging facilities. We
+ * separately control debugging based on MAC label.
+ */
+ case PRIV_DEBUG_DIFFCRED:
+ case PRIV_DEBUG_SUGID:
+ case PRIV_DEBUG_UNPRIV:
+
+ /*
+ * Allow manipulating jails.
+ */
+ case PRIV_JAIL_ATTACH:
+
+ /*
+ * Allow privilege with respect to the Partition policy, but not the
+ * Privs policy.
+ */
+ case PRIV_MAC_PARTITION:
+
+ /*
+ * Allow privilege with respect to process resource limits and login
+ * context.
+ */
+ case PRIV_PROC_LIMIT:
+ case PRIV_PROC_SETLOGIN:
+ case PRIV_PROC_SETRLIMIT:
+
+ /*
+ * Allow System V and POSIX IPC privileges.
+ */
+ case PRIV_IPC_READ:
+ case PRIV_IPC_WRITE:
+ case PRIV_IPC_ADMIN:
+ case PRIV_IPC_MSGSIZE:
+ case PRIV_MQ_ADMIN:
+
+ /*
+ * Allow certain scheduler manipulations -- possibly this should be
+ * controlled by more fine-grained policy, as potentially low
+ * integrity processes can deny CPU to higher integrity ones.
+ */
+ case PRIV_SCHED_DIFFCRED:
+ case PRIV_SCHED_SETPRIORITY:
+ case PRIV_SCHED_RTPRIO:
+ case PRIV_SCHED_SETPOLICY:
+ case PRIV_SCHED_SET:
+ case PRIV_SCHED_SETPARAM:
+
+ /*
+ * More IPC privileges.
+ */
+ case PRIV_SEM_WRITE:
+
+ /*
+ * Allow signaling privileges subject to integrity policy.
+ */
+ case PRIV_SIGNAL_DIFFCRED:
+ case PRIV_SIGNAL_SUGID:
+
+ /*
+ * Allow access to only limited sysctls from lower integrity levels;
+ * piggy-back on the Jail definition.
+ */
+ case PRIV_SYSCTL_WRITEJAIL:
+
+ /*
+ * Allow TTY-based privileges, subject to general device access using
+ * labels on TTY device nodes, but not console privilege.
+ */
+ case PRIV_TTY_DRAINWAIT:
+ case PRIV_TTY_DTRWAIT:
+ case PRIV_TTY_EXCLUSIVE:
+ case PRIV_TTY_PRISON:
+ case PRIV_TTY_STI:
+ case PRIV_TTY_SETA:
+
+ /*
+ * Grant most VFS privileges, as almost all are in practice bounded
+ * by more specific checks using labels.
+ */
+ case PRIV_VFS_READ:
+ case PRIV_VFS_WRITE:
+ case PRIV_VFS_ADMIN:
+ case PRIV_VFS_EXEC:
+ case PRIV_VFS_LOOKUP:
+ case PRIV_VFS_CHFLAGS_DEV:
+ case PRIV_VFS_CHOWN:
+ case PRIV_VFS_CHROOT:
+ case PRIV_VFS_RETAINSUGID:
+ case PRIV_VFS_EXCEEDQUOTA:
+ case PRIV_VFS_FCHROOT:
+ case PRIV_VFS_FHOPEN:
+ case PRIV_VFS_FHSTATFS:
+ case PRIV_VFS_GENERATION:
+ case PRIV_VFS_GETFH:
+ case PRIV_VFS_GETQUOTA:
+ case PRIV_VFS_LINK:
+ case PRIV_VFS_MOUNT:
+ case PRIV_VFS_MOUNT_OWNER:
+ case PRIV_VFS_MOUNT_PERM:
+ case PRIV_VFS_MOUNT_SUIDDIR:
+ case PRIV_VFS_MOUNT_NONUSER:
+ case PRIV_VFS_SETGID:
+ case PRIV_VFS_STICKYFILE:
+ case PRIV_VFS_SYSFLAGS:
+ case PRIV_VFS_UNMOUNT:
+
+ /*
+ * Allow VM privileges; it would be nice if these were subject to
+ * resource limits.
+ */
+ case PRIV_VM_MADV_PROTECT:
+ case PRIV_VM_MLOCK:
+ case PRIV_VM_MUNLOCK:
+
+ /*
+ * Allow some but not all network privileges. In general, dont allow
+ * reconfiguring the network stack, just normal use.
+ */
+ case PRIV_NETATALK_RESERVEDPORT:
+ case PRIV_NETINET_RESERVEDPORT:
+ case PRIV_NETINET_RAW:
+ case PRIV_NETINET_REUSEPORT:
+ case PRIV_NETIPX_RESERVEDPORT:
+ case PRIV_NETIPX_RAW:
+ break;
+
+ /*
+ * All remaining system privileges are allow only if the process
+ * holds privilege with respect to the Biba policy.
+ */
+ default:
+ subj = SLOT(cred->cr_label);
+ error = biba_subject_privileged(subj);
+ if (error)
+ return (error);
+ }
+ return (0);
+}
+
+static int
+biba_proc_check_debug(struct ucred *cred, struct proc *p)
+{
+ struct mac_biba *subj, *obj;
+
+ if (!biba_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(p->p_ucred->cr_label);
+
+ /* XXX: range checks */
+ if (!biba_dominate_effective(obj, subj))
+ return (ESRCH);
+ if (!biba_dominate_effective(subj, obj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+biba_proc_check_sched(struct ucred *cred, struct proc *p)
+{
+ struct mac_biba *subj, *obj;
+
+ if (!biba_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(p->p_ucred->cr_label);
+
+ /* XXX: range checks */
+ if (!biba_dominate_effective(obj, subj))
+ return (ESRCH);
+ if (!biba_dominate_effective(subj, obj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+biba_proc_check_signal(struct ucred *cred, struct proc *p, int signum)
+{
+ struct mac_biba *subj, *obj;
+
+ if (!biba_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(p->p_ucred->cr_label);
+
+ /* XXX: range checks */
+ if (!biba_dominate_effective(obj, subj))
+ return (ESRCH);
+ if (!biba_dominate_effective(subj, obj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+biba_socket_check_deliver(struct socket *so, struct label *solabel,
+ struct mbuf *m, struct label *mlabel)
+{
+ struct mac_biba *p, *s;
+
+ if (!biba_enabled)
+ return (0);
+
+ p = SLOT(mlabel);
+ s = SLOT(solabel);
+
+ return (biba_equal_effective(p, s) ? 0 : EACCES);
+}
+
+static int
+biba_socket_check_relabel(struct ucred *cred, struct socket *so,
+ struct label *solabel, struct label *newlabel)
+{
+ struct mac_biba *subj, *obj, *new;
+ int error;
+
+ new = SLOT(newlabel);
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(solabel);
+
+ /*
+ * If there is a Biba label update for the socket, it may be an
+ * update of effective.
+ */
+ error = biba_atmostflags(new, MAC_BIBA_FLAG_EFFECTIVE);
+ if (error)
+ return (error);
+
+ /*
+ * To relabel a socket, the old socket effective must be in the
+ * subject range.
+ */
+ if (!biba_effective_in_range(obj, subj))
+ return (EPERM);
+
+ /*
+ * If the Biba label is to be changed, authorize as appropriate.
+ */
+ if (new->mb_flags & MAC_BIBA_FLAG_EFFECTIVE) {
+ /*
+ * To relabel a socket, the new socket effective must be in
+ * the subject range.
+ */
+ if (!biba_effective_in_range(new, subj))
+ return (EPERM);
+
+ /*
+ * To change the Biba label on the socket to contain EQUAL,
+ * the subject must have appropriate privilege.
+ */
+ if (biba_contains_equal(new)) {
+ error = biba_subject_privileged(subj);
+ if (error)
+ return (error);
+ }
+ }
+
+ return (0);
+}
+
+static int
+biba_socket_check_visible(struct ucred *cred, struct socket *so,
+ struct label *solabel)
+{
+ struct mac_biba *subj, *obj;
+
+ if (!biba_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(solabel);
+
+ if (!biba_dominate_effective(obj, subj))
+ return (ENOENT);
+
+ return (0);
+}
+
+static void
+biba_socket_create(struct ucred *cred, struct socket *so,
+ struct label *solabel)
+{
+ struct mac_biba *source, *dest;
+
+ source = SLOT(cred->cr_label);
+ dest = SLOT(solabel);
+
+ biba_copy_effective(source, dest);
+}
+
+static void
+biba_socket_create_mbuf(struct socket *so, struct label *solabel,
+ struct mbuf *m, struct label *mlabel)
+{
+ struct mac_biba *source, *dest;
+
+ source = SLOT(solabel);
+ dest = SLOT(mlabel);
+
+ biba_copy_effective(source, dest);
+}
+
+static void
+biba_socket_newconn(struct socket *oldso, struct label *oldsolabel,
+ struct socket *newso, struct label *newsolabel)
+{
+ struct mac_biba *source, *dest;
+
+ source = SLOT(oldsolabel);
+ dest = SLOT(newsolabel);
+
+ biba_copy_effective(source, dest);
+}
+
+static void
+biba_socket_relabel(struct ucred *cred, struct socket *so,
+ struct label *solabel, struct label *newlabel)
+{
+ struct mac_biba *source, *dest;
+
+ source = SLOT(newlabel);
+ dest = SLOT(solabel);
+
+ biba_copy(source, dest);
+}
+
+static void
+biba_socketpeer_set_from_mbuf(struct mbuf *m, struct label *mlabel,
+ struct socket *so, struct label *sopeerlabel)
+{
+ struct mac_biba *source, *dest;
+
+ source = SLOT(mlabel);
+ dest = SLOT(sopeerlabel);
+
+ biba_copy_effective(source, dest);
+}
+
+static void
+biba_socketpeer_set_from_socket(struct socket *oldso,
+ struct label *oldsolabel, struct socket *newso,
+ struct label *newsopeerlabel)
+{
+ struct mac_biba *source, *dest;
+
+ source = SLOT(oldsolabel);
+ dest = SLOT(newsopeerlabel);
+
+ biba_copy_effective(source, dest);
+}
+
+static void
+biba_syncache_create(struct label *label, struct inpcb *inp)
+{
+ struct mac_biba *source, *dest;
+
+ source = SLOT(inp->inp_label);
+ dest = SLOT(label);
+ biba_copy_effective(source, dest);
+}
+
+static void
+biba_syncache_create_mbuf(struct label *sc_label, struct mbuf *m,
+ struct label *mlabel)
+{
+ struct mac_biba *source, *dest;
+
+ source = SLOT(sc_label);
+ dest = SLOT(mlabel);
+ biba_copy_effective(source, dest);
+}
+
+static int
+biba_system_check_acct(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel)
+{
+ struct mac_biba *subj, *obj;
+ int error;
+
+ if (!biba_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+
+ error = biba_subject_privileged(subj);
+ if (error)
+ return (error);
+
+ if (vplabel == NULL)
+ return (0);
+
+ obj = SLOT(vplabel);
+ if (!biba_high_effective(obj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+biba_system_check_auditctl(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel)
+{
+ struct mac_biba *subj, *obj;
+ int error;
+
+ if (!biba_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+
+ error = biba_subject_privileged(subj);
+ if (error)
+ return (error);
+
+ if (vplabel == NULL)
+ return (0);
+
+ obj = SLOT(vplabel);
+ if (!biba_high_effective(obj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+biba_system_check_auditon(struct ucred *cred, int cmd)
+{
+ struct mac_biba *subj;
+ int error;
+
+ if (!biba_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+
+ error = biba_subject_privileged(subj);
+ if (error)
+ return (error);
+
+ return (0);
+}
+
+static int
+biba_system_check_swapoff(struct ucred *cred, struct vnode *vp,
+ struct label *label)
+{
+ struct mac_biba *subj;
+ int error;
+
+ if (!biba_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+
+ error = biba_subject_privileged(subj);
+ if (error)
+ return (error);
+
+ return (0);
+}
+
+static int
+biba_system_check_swapon(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel)
+{
+ struct mac_biba *subj, *obj;
+ int error;
+
+ if (!biba_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(vplabel);
+
+ error = biba_subject_privileged(subj);
+ if (error)
+ return (error);
+
+ if (!biba_high_effective(obj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+biba_system_check_sysctl(struct ucred *cred, struct sysctl_oid *oidp,
+ void *arg1, int arg2, struct sysctl_req *req)
+{
+ struct mac_biba *subj;
+ int error;
+
+ if (!biba_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+
+ /*
+ * Treat sysctl variables without CTLFLAG_ANYBODY flag as biba/high,
+ * but also require privilege to change them.
+ */
+ if (req->newptr != NULL && (oidp->oid_kind & CTLFLAG_ANYBODY) == 0) {
+ if (!biba_subject_dominate_high(subj))
+ return (EACCES);
+
+ error = biba_subject_privileged(subj);
+ if (error)
+ return (error);
+ }
+
+ return (0);
+}
+
+static void
+biba_sysvmsg_cleanup(struct label *msglabel)
+{
+
+ bzero(SLOT(msglabel), sizeof(struct mac_biba));
+}
+
+static void
+biba_sysvmsg_create(struct ucred *cred, struct msqid_kernel *msqkptr,
+ struct label *msqlabel, struct msg *msgptr, struct label *msglabel)
+{
+ struct mac_biba *source, *dest;
+
+ /* Ignore the msgq label */
+ source = SLOT(cred->cr_label);
+ dest = SLOT(msglabel);
+
+ biba_copy_effective(source, dest);
+}
+
+static int
+biba_sysvmsq_check_msgrcv(struct ucred *cred, struct msg *msgptr,
+ struct label *msglabel)
+{
+ struct mac_biba *subj, *obj;
+
+ if (!biba_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(msglabel);
+
+ if (!biba_dominate_effective(obj, subj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+biba_sysvmsq_check_msgrmid(struct ucred *cred, struct msg *msgptr,
+ struct label *msglabel)
+{
+ struct mac_biba *subj, *obj;
+
+ if (!biba_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(msglabel);
+
+ if (!biba_dominate_effective(subj, obj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+biba_sysvmsq_check_msqget(struct ucred *cred, struct msqid_kernel *msqkptr,
+ struct label *msqklabel)
+{
+ struct mac_biba *subj, *obj;
+
+ if (!biba_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(msqklabel);
+
+ if (!biba_dominate_effective(obj, subj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+biba_sysvmsq_check_msqsnd(struct ucred *cred, struct msqid_kernel *msqkptr,
+ struct label *msqklabel)
+{
+ struct mac_biba *subj, *obj;
+
+ if (!biba_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(msqklabel);
+
+ if (!biba_dominate_effective(subj, obj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+biba_sysvmsq_check_msqrcv(struct ucred *cred, struct msqid_kernel *msqkptr,
+ struct label *msqklabel)
+{
+ struct mac_biba *subj, *obj;
+
+ if (!biba_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(msqklabel);
+
+ if (!biba_dominate_effective(obj, subj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+biba_sysvmsq_check_msqctl(struct ucred *cred, struct msqid_kernel *msqkptr,
+ struct label *msqklabel, int cmd)
+{
+ struct mac_biba *subj, *obj;
+
+ if (!biba_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(msqklabel);
+
+ switch(cmd) {
+ case IPC_RMID:
+ case IPC_SET:
+ if (!biba_dominate_effective(subj, obj))
+ return (EACCES);
+ break;
+
+ case IPC_STAT:
+ if (!biba_dominate_effective(obj, subj))
+ return (EACCES);
+ break;
+
+ default:
+ return (EACCES);
+ }
+
+ return (0);
+}
+
+static void
+biba_sysvmsq_cleanup(struct label *msqlabel)
+{
+
+ bzero(SLOT(msqlabel), sizeof(struct mac_biba));
+}
+
+static void
+biba_sysvmsq_create(struct ucred *cred, struct msqid_kernel *msqkptr,
+ struct label *msqlabel)
+{
+ struct mac_biba *source, *dest;
+
+ source = SLOT(cred->cr_label);
+ dest = SLOT(msqlabel);
+
+ biba_copy_effective(source, dest);
+}
+
+static int
+biba_sysvsem_check_semctl(struct ucred *cred, struct semid_kernel *semakptr,
+ struct label *semaklabel, int cmd)
+{
+ struct mac_biba *subj, *obj;
+
+ if (!biba_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(semaklabel);
+
+ switch(cmd) {
+ case IPC_RMID:
+ case IPC_SET:
+ case SETVAL:
+ case SETALL:
+ if (!biba_dominate_effective(subj, obj))
+ return (EACCES);
+ break;
+
+ case IPC_STAT:
+ case GETVAL:
+ case GETPID:
+ case GETNCNT:
+ case GETZCNT:
+ case GETALL:
+ if (!biba_dominate_effective(obj, subj))
+ return (EACCES);
+ break;
+
+ default:
+ return (EACCES);
+ }
+
+ return (0);
+}
+
+static int
+biba_sysvsem_check_semget(struct ucred *cred, struct semid_kernel *semakptr,
+ struct label *semaklabel)
+{
+ struct mac_biba *subj, *obj;
+
+ if (!biba_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(semaklabel);
+
+ if (!biba_dominate_effective(obj, subj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+biba_sysvsem_check_semop(struct ucred *cred, struct semid_kernel *semakptr,
+ struct label *semaklabel, size_t accesstype)
+{
+ struct mac_biba *subj, *obj;
+
+ if (!biba_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(semaklabel);
+
+ if (accesstype & SEM_R)
+ if (!biba_dominate_effective(obj, subj))
+ return (EACCES);
+
+ if (accesstype & SEM_A)
+ if (!biba_dominate_effective(subj, obj))
+ return (EACCES);
+
+ return (0);
+}
+
+static void
+biba_sysvsem_cleanup(struct label *semalabel)
+{
+
+ bzero(SLOT(semalabel), sizeof(struct mac_biba));
+}
+
+static void
+biba_sysvsem_create(struct ucred *cred, struct semid_kernel *semakptr,
+ struct label *semalabel)
+{
+ struct mac_biba *source, *dest;
+
+ source = SLOT(cred->cr_label);
+ dest = SLOT(semalabel);
+
+ biba_copy_effective(source, dest);
+}
+
+static int
+biba_sysvshm_check_shmat(struct ucred *cred, struct shmid_kernel *shmsegptr,
+ struct label *shmseglabel, int shmflg)
+{
+ struct mac_biba *subj, *obj;
+
+ if (!biba_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(shmseglabel);
+
+ if (!biba_dominate_effective(obj, subj))
+ return (EACCES);
+ if ((shmflg & SHM_RDONLY) == 0) {
+ if (!biba_dominate_effective(subj, obj))
+ return (EACCES);
+ }
+
+ return (0);
+}
+
+static int
+biba_sysvshm_check_shmctl(struct ucred *cred, struct shmid_kernel *shmsegptr,
+ struct label *shmseglabel, int cmd)
+{
+ struct mac_biba *subj, *obj;
+
+ if (!biba_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(shmseglabel);
+
+ switch(cmd) {
+ case IPC_RMID:
+ case IPC_SET:
+ if (!biba_dominate_effective(subj, obj))
+ return (EACCES);
+ break;
+
+ case IPC_STAT:
+ case SHM_STAT:
+ if (!biba_dominate_effective(obj, subj))
+ return (EACCES);
+ break;
+
+ default:
+ return (EACCES);
+ }
+
+ return (0);
+}
+
+static int
+biba_sysvshm_check_shmget(struct ucred *cred, struct shmid_kernel *shmsegptr,
+ struct label *shmseglabel, int shmflg)
+{
+ struct mac_biba *subj, *obj;
+
+ if (!biba_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(shmseglabel);
+
+ if (!biba_dominate_effective(obj, subj))
+ return (EACCES);
+
+ return (0);
+}
+
+static void
+biba_sysvshm_cleanup(struct label *shmlabel)
+{
+
+ bzero(SLOT(shmlabel), sizeof(struct mac_biba));
+}
+
+static void
+biba_sysvshm_create(struct ucred *cred, struct shmid_kernel *shmsegptr,
+ struct label *shmlabel)
+{
+ struct mac_biba *source, *dest;
+
+ source = SLOT(cred->cr_label);
+ dest = SLOT(shmlabel);
+
+ biba_copy_effective(source, dest);
+}
+
+static int
+biba_vnode_associate_extattr(struct mount *mp, struct label *mplabel,
+ struct vnode *vp, struct label *vplabel)
+{
+ struct mac_biba mb_temp, *source, *dest;
+ int buflen, error;
+
+ source = SLOT(mplabel);
+ dest = SLOT(vplabel);
+
+ buflen = sizeof(mb_temp);
+ bzero(&mb_temp, buflen);
+
+ error = vn_extattr_get(vp, IO_NODELOCKED, MAC_BIBA_EXTATTR_NAMESPACE,
+ MAC_BIBA_EXTATTR_NAME, &buflen, (char *) &mb_temp, curthread);
+ if (error == ENOATTR || error == EOPNOTSUPP) {
+ /* Fall back to the mntlabel. */
+ biba_copy_effective(source, dest);
+ return (0);
+ } else if (error)
+ return (error);
+
+ if (buflen != sizeof(mb_temp)) {
+ printf("biba_vnode_associate_extattr: bad size %d\n",
+ buflen);
+ return (EPERM);
+ }
+ if (biba_valid(&mb_temp) != 0) {
+ printf("biba_vnode_associate_extattr: invalid\n");
+ return (EPERM);
+ }
+ if ((mb_temp.mb_flags & MAC_BIBA_FLAGS_BOTH) !=
+ MAC_BIBA_FLAG_EFFECTIVE) {
+ printf("biba_vnode_associate_extattr: not effective\n");
+ return (EPERM);
+ }
+
+ biba_copy_effective(&mb_temp, dest);
+ return (0);
+}
+
+static void
+biba_vnode_associate_singlelabel(struct mount *mp, struct label *mplabel,
+ struct vnode *vp, struct label *vplabel)
+{
+ struct mac_biba *source, *dest;
+
+ source = SLOT(mplabel);
+ dest = SLOT(vplabel);
+
+ biba_copy_effective(source, dest);
+}
+
+static int
+biba_vnode_check_chdir(struct ucred *cred, struct vnode *dvp,
+ struct label *dvplabel)
+{
+ struct mac_biba *subj, *obj;
+
+ if (!biba_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(dvplabel);
+
+ if (!biba_dominate_effective(obj, subj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+biba_vnode_check_chroot(struct ucred *cred, struct vnode *dvp,
+ struct label *dvplabel)
+{
+ struct mac_biba *subj, *obj;
+
+ if (!biba_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(dvplabel);
+
+ if (!biba_dominate_effective(obj, subj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+biba_vnode_check_create(struct ucred *cred, struct vnode *dvp,
+ struct label *dvplabel, struct componentname *cnp, struct vattr *vap)
+{
+ struct mac_biba *subj, *obj;
+
+ if (!biba_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(dvplabel);
+
+ if (!biba_dominate_effective(subj, obj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+biba_vnode_check_deleteacl(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, acl_type_t type)
+{
+ struct mac_biba *subj, *obj;
+
+ if (!biba_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(vplabel);
+
+ if (!biba_dominate_effective(subj, obj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+biba_vnode_check_deleteextattr(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, int attrnamespace, const char *name)
+{
+ struct mac_biba *subj, *obj;
+
+ if (!biba_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(vplabel);
+
+ if (!biba_dominate_effective(subj, obj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+biba_vnode_check_exec(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, struct image_params *imgp,
+ struct label *execlabel)
+{
+ struct mac_biba *subj, *obj, *exec;
+ int error;
+
+ if (execlabel != NULL) {
+ /*
+ * We currently don't permit labels to be changed at
+ * exec-time as part of Biba, so disallow non-NULL Biba label
+ * elements in the execlabel.
+ */
+ exec = SLOT(execlabel);
+ error = biba_atmostflags(exec, 0);
+ if (error)
+ return (error);
+ }
+
+ if (!biba_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(vplabel);
+
+ if (!biba_dominate_effective(obj, subj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+biba_vnode_check_getacl(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, acl_type_t type)
+{
+ struct mac_biba *subj, *obj;
+
+ if (!biba_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(vplabel);
+
+ if (!biba_dominate_effective(obj, subj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+biba_vnode_check_getextattr(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, int attrnamespace, const char *name,
+ struct uio *uio)
+{
+ struct mac_biba *subj, *obj;
+
+ if (!biba_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(vplabel);
+
+ if (!biba_dominate_effective(obj, subj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+biba_vnode_check_link(struct ucred *cred, struct vnode *dvp,
+ struct label *dvplabel, struct vnode *vp, struct label *vplabel,
+ struct componentname *cnp)
+{
+ struct mac_biba *subj, *obj;
+
+ if (!biba_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(dvplabel);
+
+ if (!biba_dominate_effective(subj, obj))
+ return (EACCES);
+
+ obj = SLOT(vplabel);
+
+ if (!biba_dominate_effective(subj, obj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+biba_vnode_check_listextattr(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, int attrnamespace)
+{
+ struct mac_biba *subj, *obj;
+
+ if (!biba_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(vplabel);
+
+ if (!biba_dominate_effective(obj, subj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+biba_vnode_check_lookup(struct ucred *cred, struct vnode *dvp,
+ struct label *dvplabel, struct componentname *cnp)
+{
+ struct mac_biba *subj, *obj;
+
+ if (!biba_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(dvplabel);
+
+ if (!biba_dominate_effective(obj, subj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+biba_vnode_check_mmap(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, int prot, int flags)
+{
+ struct mac_biba *subj, *obj;
+
+ /*
+ * Rely on the use of open()-time protections to handle
+ * non-revocation cases.
+ */
+ if (!biba_enabled || !revocation_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(vplabel);
+
+ if (prot & (VM_PROT_READ | VM_PROT_EXECUTE)) {
+ if (!biba_dominate_effective(obj, subj))
+ return (EACCES);
+ }
+ if (((prot & VM_PROT_WRITE) != 0) && ((flags & MAP_SHARED) != 0)) {
+ if (!biba_dominate_effective(subj, obj))
+ return (EACCES);
+ }
+
+ return (0);
+}
+
+static int
+biba_vnode_check_open(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, accmode_t accmode)
+{
+ struct mac_biba *subj, *obj;
+
+ if (!biba_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(vplabel);
+
+ /* XXX privilege override for admin? */
+ if (accmode & (VREAD | VEXEC | VSTAT)) {
+ if (!biba_dominate_effective(obj, subj))
+ return (EACCES);
+ }
+ if (accmode & (VWRITE | VAPPEND | VADMIN)) {
+ if (!biba_dominate_effective(subj, obj))
+ return (EACCES);
+ }
+
+ return (0);
+}
+
+static int
+biba_vnode_check_poll(struct ucred *active_cred, struct ucred *file_cred,
+ struct vnode *vp, struct label *vplabel)
+{
+ struct mac_biba *subj, *obj;
+
+ if (!biba_enabled || !revocation_enabled)
+ return (0);
+
+ subj = SLOT(active_cred->cr_label);
+ obj = SLOT(vplabel);
+
+ if (!biba_dominate_effective(obj, subj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+biba_vnode_check_read(struct ucred *active_cred, struct ucred *file_cred,
+ struct vnode *vp, struct label *vplabel)
+{
+ struct mac_biba *subj, *obj;
+
+ if (!biba_enabled || !revocation_enabled)
+ return (0);
+
+ subj = SLOT(active_cred->cr_label);
+ obj = SLOT(vplabel);
+
+ if (!biba_dominate_effective(obj, subj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+biba_vnode_check_readdir(struct ucred *cred, struct vnode *dvp,
+ struct label *dvplabel)
+{
+ struct mac_biba *subj, *obj;
+
+ if (!biba_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(dvplabel);
+
+ if (!biba_dominate_effective(obj, subj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+biba_vnode_check_readlink(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel)
+{
+ struct mac_biba *subj, *obj;
+
+ if (!biba_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(vplabel);
+
+ if (!biba_dominate_effective(obj, subj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+biba_vnode_check_relabel(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, struct label *newlabel)
+{
+ struct mac_biba *old, *new, *subj;
+ int error;
+
+ old = SLOT(vplabel);
+ new = SLOT(newlabel);
+ subj = SLOT(cred->cr_label);
+
+ /*
+ * If there is a Biba label update for the vnode, it must be a
+ * effective label.
+ */
+ error = biba_atmostflags(new, MAC_BIBA_FLAG_EFFECTIVE);
+ if (error)
+ return (error);
+
+ /*
+ * To perform a relabel of the vnode (Biba label or not), Biba must
+ * authorize the relabel.
+ */
+ if (!biba_effective_in_range(old, subj))
+ return (EPERM);
+
+ /*
+ * If the Biba label is to be changed, authorize as appropriate.
+ */
+ if (new->mb_flags & MAC_BIBA_FLAG_EFFECTIVE) {
+ /*
+ * To change the Biba label on a vnode, the new vnode label
+ * must be in the subject range.
+ */
+ if (!biba_effective_in_range(new, subj))
+ return (EPERM);
+
+ /*
+ * To change the Biba label on the vnode to be EQUAL, the
+ * subject must have appropriate privilege.
+ */
+ if (biba_contains_equal(new)) {
+ error = biba_subject_privileged(subj);
+ if (error)
+ return (error);
+ }
+ }
+
+ return (0);
+}
+
+static int
+biba_vnode_check_rename_from(struct ucred *cred, struct vnode *dvp,
+ struct label *dvplabel, struct vnode *vp, struct label *vplabel,
+ struct componentname *cnp)
+{
+ struct mac_biba *subj, *obj;
+
+ if (!biba_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(dvplabel);
+
+ if (!biba_dominate_effective(subj, obj))
+ return (EACCES);
+
+ obj = SLOT(vplabel);
+
+ if (!biba_dominate_effective(subj, obj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+biba_vnode_check_rename_to(struct ucred *cred, struct vnode *dvp,
+ struct label *dvplabel, struct vnode *vp, struct label *vplabel,
+ int samedir, struct componentname *cnp)
+{
+ struct mac_biba *subj, *obj;
+
+ if (!biba_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(dvplabel);
+
+ if (!biba_dominate_effective(subj, obj))
+ return (EACCES);
+
+ if (vp != NULL) {
+ obj = SLOT(vplabel);
+
+ if (!biba_dominate_effective(subj, obj))
+ return (EACCES);
+ }
+
+ return (0);
+}
+
+static int
+biba_vnode_check_revoke(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel)
+{
+ struct mac_biba *subj, *obj;
+
+ if (!biba_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(vplabel);
+
+ if (!biba_dominate_effective(subj, obj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+biba_vnode_check_setacl(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, acl_type_t type, struct acl *acl)
+{
+ struct mac_biba *subj, *obj;
+
+ if (!biba_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(vplabel);
+
+ if (!biba_dominate_effective(subj, obj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+biba_vnode_check_setextattr(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, int attrnamespace, const char *name,
+ struct uio *uio)
+{
+ struct mac_biba *subj, *obj;
+
+ if (!biba_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(vplabel);
+
+ if (!biba_dominate_effective(subj, obj))
+ return (EACCES);
+
+ /* XXX: protect the MAC EA in a special way? */
+
+ return (0);
+}
+
+static int
+biba_vnode_check_setflags(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, u_long flags)
+{
+ struct mac_biba *subj, *obj;
+
+ if (!biba_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(vplabel);
+
+ if (!biba_dominate_effective(subj, obj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+biba_vnode_check_setmode(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, mode_t mode)
+{
+ struct mac_biba *subj, *obj;
+
+ if (!biba_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(vplabel);
+
+ if (!biba_dominate_effective(subj, obj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+biba_vnode_check_setowner(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, uid_t uid, gid_t gid)
+{
+ struct mac_biba *subj, *obj;
+
+ if (!biba_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(vplabel);
+
+ if (!biba_dominate_effective(subj, obj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+biba_vnode_check_setutimes(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, struct timespec atime, struct timespec mtime)
+{
+ struct mac_biba *subj, *obj;
+
+ if (!biba_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(vplabel);
+
+ if (!biba_dominate_effective(subj, obj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+biba_vnode_check_stat(struct ucred *active_cred, struct ucred *file_cred,
+ struct vnode *vp, struct label *vplabel)
+{
+ struct mac_biba *subj, *obj;
+
+ if (!biba_enabled)
+ return (0);
+
+ subj = SLOT(active_cred->cr_label);
+ obj = SLOT(vplabel);
+
+ if (!biba_dominate_effective(obj, subj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+biba_vnode_check_unlink(struct ucred *cred, struct vnode *dvp,
+ struct label *dvplabel, struct vnode *vp, struct label *vplabel,
+ struct componentname *cnp)
+{
+ struct mac_biba *subj, *obj;
+
+ if (!biba_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(dvplabel);
+
+ if (!biba_dominate_effective(subj, obj))
+ return (EACCES);
+
+ obj = SLOT(vplabel);
+
+ if (!biba_dominate_effective(subj, obj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+biba_vnode_check_write(struct ucred *active_cred,
+ struct ucred *file_cred, struct vnode *vp, struct label *vplabel)
+{
+ struct mac_biba *subj, *obj;
+
+ if (!biba_enabled || !revocation_enabled)
+ return (0);
+
+ subj = SLOT(active_cred->cr_label);
+ obj = SLOT(vplabel);
+
+ if (!biba_dominate_effective(subj, obj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+biba_vnode_create_extattr(struct ucred *cred, struct mount *mp,
+ struct label *mplabel, struct vnode *dvp, struct label *dvplabel,
+ struct vnode *vp, struct label *vplabel, struct componentname *cnp)
+{
+ struct mac_biba *source, *dest, mb_temp;
+ size_t buflen;
+ int error;
+
+ buflen = sizeof(mb_temp);
+ bzero(&mb_temp, buflen);
+
+ source = SLOT(cred->cr_label);
+ dest = SLOT(vplabel);
+ biba_copy_effective(source, &mb_temp);
+
+ error = vn_extattr_set(vp, IO_NODELOCKED, MAC_BIBA_EXTATTR_NAMESPACE,
+ MAC_BIBA_EXTATTR_NAME, buflen, (char *) &mb_temp, curthread);
+ if (error == 0)
+ biba_copy_effective(source, dest);
+ return (error);
+}
+
+static void
+biba_vnode_relabel(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, struct label *newlabel)
+{
+ struct mac_biba *source, *dest;
+
+ source = SLOT(newlabel);
+ dest = SLOT(vplabel);
+
+ biba_copy(source, dest);
+}
+
+static int
+biba_vnode_setlabel_extattr(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, struct label *intlabel)
+{
+ struct mac_biba *source, mb_temp;
+ size_t buflen;
+ int error;
+
+ buflen = sizeof(mb_temp);
+ bzero(&mb_temp, buflen);
+
+ source = SLOT(intlabel);
+ if ((source->mb_flags & MAC_BIBA_FLAG_EFFECTIVE) == 0)
+ return (0);
+
+ biba_copy_effective(source, &mb_temp);
+
+ error = vn_extattr_set(vp, IO_NODELOCKED, MAC_BIBA_EXTATTR_NAMESPACE,
+ MAC_BIBA_EXTATTR_NAME, buflen, (char *) &mb_temp, curthread);
+ return (error);
+}
+
+static struct mac_policy_ops mac_biba_ops =
+{
+ .mpo_init = biba_init,
+
+ .mpo_bpfdesc_check_receive = biba_bpfdesc_check_receive,
+ .mpo_bpfdesc_create = biba_bpfdesc_create,
+ .mpo_bpfdesc_create_mbuf = biba_bpfdesc_create_mbuf,
+ .mpo_bpfdesc_destroy_label = biba_destroy_label,
+ .mpo_bpfdesc_init_label = biba_init_label,
+
+ .mpo_cred_associate_nfsd = biba_cred_associate_nfsd,
+ .mpo_cred_check_relabel = biba_cred_check_relabel,
+ .mpo_cred_check_visible = biba_cred_check_visible,
+ .mpo_cred_copy_label = biba_copy_label,
+ .mpo_cred_create_init = biba_cred_create_init,
+ .mpo_cred_create_swapper = biba_cred_create_swapper,
+ .mpo_cred_destroy_label = biba_destroy_label,
+ .mpo_cred_externalize_label = biba_externalize_label,
+ .mpo_cred_init_label = biba_init_label,
+ .mpo_cred_internalize_label = biba_internalize_label,
+ .mpo_cred_relabel = biba_cred_relabel,
+
+ .mpo_devfs_create_device = biba_devfs_create_device,
+ .mpo_devfs_create_directory = biba_devfs_create_directory,
+ .mpo_devfs_create_symlink = biba_devfs_create_symlink,
+ .mpo_devfs_destroy_label = biba_destroy_label,
+ .mpo_devfs_init_label = biba_init_label,
+ .mpo_devfs_update = biba_devfs_update,
+ .mpo_devfs_vnode_associate = biba_devfs_vnode_associate,
+
+ .mpo_ifnet_check_relabel = biba_ifnet_check_relabel,
+ .mpo_ifnet_check_transmit = biba_ifnet_check_transmit,
+ .mpo_ifnet_copy_label = biba_copy_label,
+ .mpo_ifnet_create = biba_ifnet_create,
+ .mpo_ifnet_create_mbuf = biba_ifnet_create_mbuf,
+ .mpo_ifnet_destroy_label = biba_destroy_label,
+ .mpo_ifnet_externalize_label = biba_externalize_label,
+ .mpo_ifnet_init_label = biba_init_label,
+ .mpo_ifnet_internalize_label = biba_internalize_label,
+ .mpo_ifnet_relabel = biba_ifnet_relabel,
+
+ .mpo_inpcb_check_deliver = biba_inpcb_check_deliver,
+ .mpo_inpcb_check_visible = biba_inpcb_check_visible,
+ .mpo_inpcb_create = biba_inpcb_create,
+ .mpo_inpcb_create_mbuf = biba_inpcb_create_mbuf,
+ .mpo_inpcb_destroy_label = biba_destroy_label,
+ .mpo_inpcb_init_label = biba_init_label_waitcheck,
+ .mpo_inpcb_sosetlabel = biba_inpcb_sosetlabel,
+
+ .mpo_ip6q_create = biba_ip6q_create,
+ .mpo_ip6q_destroy_label = biba_destroy_label,
+ .mpo_ip6q_init_label = biba_init_label_waitcheck,
+ .mpo_ip6q_match = biba_ip6q_match,
+ .mpo_ip6q_reassemble = biba_ip6q_reassemble,
+ .mpo_ip6q_update = biba_ip6q_update,
+
+ .mpo_ipq_create = biba_ipq_create,
+ .mpo_ipq_destroy_label = biba_destroy_label,
+ .mpo_ipq_init_label = biba_init_label_waitcheck,
+ .mpo_ipq_match = biba_ipq_match,
+ .mpo_ipq_reassemble = biba_ipq_reassemble,
+ .mpo_ipq_update = biba_ipq_update,
+
+ .mpo_kld_check_load = biba_kld_check_load,
+
+ .mpo_mbuf_copy_label = biba_copy_label,
+ .mpo_mbuf_destroy_label = biba_destroy_label,
+ .mpo_mbuf_init_label = biba_init_label_waitcheck,
+
+ .mpo_mount_check_stat = biba_mount_check_stat,
+ .mpo_mount_create = biba_mount_create,
+ .mpo_mount_destroy_label = biba_destroy_label,
+ .mpo_mount_init_label = biba_init_label,
+
+ .mpo_netatalk_aarp_send = biba_netatalk_aarp_send,
+
+ .mpo_netinet_arp_send = biba_netinet_arp_send,
+ .mpo_netinet_firewall_reply = biba_netinet_firewall_reply,
+ .mpo_netinet_firewall_send = biba_netinet_firewall_send,
+ .mpo_netinet_fragment = biba_netinet_fragment,
+ .mpo_netinet_icmp_reply = biba_netinet_icmp_reply,
+ .mpo_netinet_igmp_send = biba_netinet_igmp_send,
+
+ .mpo_netinet6_nd6_send = biba_netinet6_nd6_send,
+
+ .mpo_pipe_check_ioctl = biba_pipe_check_ioctl,
+ .mpo_pipe_check_poll = biba_pipe_check_poll,
+ .mpo_pipe_check_read = biba_pipe_check_read,
+ .mpo_pipe_check_relabel = biba_pipe_check_relabel,
+ .mpo_pipe_check_stat = biba_pipe_check_stat,
+ .mpo_pipe_check_write = biba_pipe_check_write,
+ .mpo_pipe_copy_label = biba_copy_label,
+ .mpo_pipe_create = biba_pipe_create,
+ .mpo_pipe_destroy_label = biba_destroy_label,
+ .mpo_pipe_externalize_label = biba_externalize_label,
+ .mpo_pipe_init_label = biba_init_label,
+ .mpo_pipe_internalize_label = biba_internalize_label,
+ .mpo_pipe_relabel = biba_pipe_relabel,
+
+ .mpo_posixsem_check_getvalue = biba_posixsem_check_rdonly,
+ .mpo_posixsem_check_open = biba_posixsem_check_openunlink,
+ .mpo_posixsem_check_post = biba_posixsem_check_write,
+ .mpo_posixsem_check_stat = biba_posixsem_check_rdonly,
+ .mpo_posixsem_check_unlink = biba_posixsem_check_openunlink,
+ .mpo_posixsem_check_wait = biba_posixsem_check_write,
+ .mpo_posixsem_create = biba_posixsem_create,
+ .mpo_posixsem_destroy_label = biba_destroy_label,
+ .mpo_posixsem_init_label = biba_init_label,
+
+ .mpo_priv_check = biba_priv_check,
+
+ .mpo_proc_check_debug = biba_proc_check_debug,
+ .mpo_proc_check_sched = biba_proc_check_sched,
+ .mpo_proc_check_signal = biba_proc_check_signal,
+
+ .mpo_socket_check_deliver = biba_socket_check_deliver,
+ .mpo_socket_check_relabel = biba_socket_check_relabel,
+ .mpo_socket_check_visible = biba_socket_check_visible,
+ .mpo_socket_copy_label = biba_copy_label,
+ .mpo_socket_create = biba_socket_create,
+ .mpo_socket_create_mbuf = biba_socket_create_mbuf,
+ .mpo_socket_destroy_label = biba_destroy_label,
+ .mpo_socket_externalize_label = biba_externalize_label,
+ .mpo_socket_init_label = biba_init_label_waitcheck,
+ .mpo_socket_internalize_label = biba_internalize_label,
+ .mpo_socket_newconn = biba_socket_newconn,
+ .mpo_socket_relabel = biba_socket_relabel,
+
+ .mpo_socketpeer_destroy_label = biba_destroy_label,
+ .mpo_socketpeer_externalize_label = biba_externalize_label,
+ .mpo_socketpeer_init_label = biba_init_label_waitcheck,
+ .mpo_socketpeer_set_from_mbuf = biba_socketpeer_set_from_mbuf,
+ .mpo_socketpeer_set_from_socket = biba_socketpeer_set_from_socket,
+
+ .mpo_syncache_create = biba_syncache_create,
+ .mpo_syncache_create_mbuf = biba_syncache_create_mbuf,
+ .mpo_syncache_destroy_label = biba_destroy_label,
+ .mpo_syncache_init_label = biba_init_label_waitcheck,
+
+ .mpo_system_check_acct = biba_system_check_acct,
+ .mpo_system_check_auditctl = biba_system_check_auditctl,
+ .mpo_system_check_auditon = biba_system_check_auditon,
+ .mpo_system_check_swapoff = biba_system_check_swapoff,
+ .mpo_system_check_swapon = biba_system_check_swapon,
+ .mpo_system_check_sysctl = biba_system_check_sysctl,
+
+ .mpo_sysvmsg_cleanup = biba_sysvmsg_cleanup,
+ .mpo_sysvmsg_create = biba_sysvmsg_create,
+ .mpo_sysvmsg_destroy_label = biba_destroy_label,
+ .mpo_sysvmsg_init_label = biba_init_label,
+
+ .mpo_sysvmsq_check_msgrcv = biba_sysvmsq_check_msgrcv,
+ .mpo_sysvmsq_check_msgrmid = biba_sysvmsq_check_msgrmid,
+ .mpo_sysvmsq_check_msqget = biba_sysvmsq_check_msqget,
+ .mpo_sysvmsq_check_msqsnd = biba_sysvmsq_check_msqsnd,
+ .mpo_sysvmsq_check_msqrcv = biba_sysvmsq_check_msqrcv,
+ .mpo_sysvmsq_check_msqctl = biba_sysvmsq_check_msqctl,
+ .mpo_sysvmsq_cleanup = biba_sysvmsq_cleanup,
+ .mpo_sysvmsq_create = biba_sysvmsq_create,
+ .mpo_sysvmsq_destroy_label = biba_destroy_label,
+ .mpo_sysvmsq_init_label = biba_init_label,
+
+ .mpo_sysvsem_check_semctl = biba_sysvsem_check_semctl,
+ .mpo_sysvsem_check_semget = biba_sysvsem_check_semget,
+ .mpo_sysvsem_check_semop = biba_sysvsem_check_semop,
+ .mpo_sysvsem_cleanup = biba_sysvsem_cleanup,
+ .mpo_sysvsem_create = biba_sysvsem_create,
+ .mpo_sysvsem_destroy_label = biba_destroy_label,
+ .mpo_sysvsem_init_label = biba_init_label,
+
+ .mpo_sysvshm_check_shmat = biba_sysvshm_check_shmat,
+ .mpo_sysvshm_check_shmctl = biba_sysvshm_check_shmctl,
+ .mpo_sysvshm_check_shmget = biba_sysvshm_check_shmget,
+ .mpo_sysvshm_cleanup = biba_sysvshm_cleanup,
+ .mpo_sysvshm_create = biba_sysvshm_create,
+ .mpo_sysvshm_destroy_label = biba_destroy_label,
+ .mpo_sysvshm_init_label = biba_init_label,
+
+ .mpo_vnode_associate_extattr = biba_vnode_associate_extattr,
+ .mpo_vnode_associate_singlelabel = biba_vnode_associate_singlelabel,
+ .mpo_vnode_check_access = biba_vnode_check_open,
+ .mpo_vnode_check_chdir = biba_vnode_check_chdir,
+ .mpo_vnode_check_chroot = biba_vnode_check_chroot,
+ .mpo_vnode_check_create = biba_vnode_check_create,
+ .mpo_vnode_check_deleteacl = biba_vnode_check_deleteacl,
+ .mpo_vnode_check_deleteextattr = biba_vnode_check_deleteextattr,
+ .mpo_vnode_check_exec = biba_vnode_check_exec,
+ .mpo_vnode_check_getacl = biba_vnode_check_getacl,
+ .mpo_vnode_check_getextattr = biba_vnode_check_getextattr,
+ .mpo_vnode_check_link = biba_vnode_check_link,
+ .mpo_vnode_check_listextattr = biba_vnode_check_listextattr,
+ .mpo_vnode_check_lookup = biba_vnode_check_lookup,
+ .mpo_vnode_check_mmap = biba_vnode_check_mmap,
+ .mpo_vnode_check_open = biba_vnode_check_open,
+ .mpo_vnode_check_poll = biba_vnode_check_poll,
+ .mpo_vnode_check_read = biba_vnode_check_read,
+ .mpo_vnode_check_readdir = biba_vnode_check_readdir,
+ .mpo_vnode_check_readlink = biba_vnode_check_readlink,
+ .mpo_vnode_check_relabel = biba_vnode_check_relabel,
+ .mpo_vnode_check_rename_from = biba_vnode_check_rename_from,
+ .mpo_vnode_check_rename_to = biba_vnode_check_rename_to,
+ .mpo_vnode_check_revoke = biba_vnode_check_revoke,
+ .mpo_vnode_check_setacl = biba_vnode_check_setacl,
+ .mpo_vnode_check_setextattr = biba_vnode_check_setextattr,
+ .mpo_vnode_check_setflags = biba_vnode_check_setflags,
+ .mpo_vnode_check_setmode = biba_vnode_check_setmode,
+ .mpo_vnode_check_setowner = biba_vnode_check_setowner,
+ .mpo_vnode_check_setutimes = biba_vnode_check_setutimes,
+ .mpo_vnode_check_stat = biba_vnode_check_stat,
+ .mpo_vnode_check_unlink = biba_vnode_check_unlink,
+ .mpo_vnode_check_write = biba_vnode_check_write,
+ .mpo_vnode_create_extattr = biba_vnode_create_extattr,
+ .mpo_vnode_copy_label = biba_copy_label,
+ .mpo_vnode_destroy_label = biba_destroy_label,
+ .mpo_vnode_externalize_label = biba_externalize_label,
+ .mpo_vnode_init_label = biba_init_label,
+ .mpo_vnode_internalize_label = biba_internalize_label,
+ .mpo_vnode_relabel = biba_vnode_relabel,
+ .mpo_vnode_setlabel_extattr = biba_vnode_setlabel_extattr,
+};
+
+#define BIBA_OBJECTS (MPC_OBJECT_CRED | \
+ /* MPC_OBJECT_PROC | */ \
+ MPC_OBJECT_VNODE | \
+ MPC_OBJECT_INPCB | \
+ MPC_OBJECT_SOCKET | \
+ MPC_OBJECT_DEVFS | \
+ MPC_OBJECT_MBUF | \
+ MPC_OBJECT_IPQ | \
+ MPC_OBJECT_IFNET | \
+ MPC_OBJECT_BPFDESC | \
+ MPC_OBJECT_PIPE | \
+ MPC_OBJECT_MOUNT | \
+ MPC_OBJECT_POSIXSEM | \
+ /* MPC_OBJECT_POSIXSHM | */ \
+ MPC_OBJECT_SYSVMSG | \
+ MPC_OBJECT_SYSVMSQ | \
+ MPC_OBJECT_SYSVSEM | \
+ MPC_OBJECT_SYSVSHM | \
+ MPC_OBJECT_SYNCACHE)
+
+MAC_POLICY_SET(&mac_biba_ops, mac_biba, "TrustedBSD MAC/Biba",
+ MPC_LOADTIME_FLAG_NOTLATE, &biba_slot, BIBA_OBJECTS);
diff --git a/sys/security/mac_biba/mac_biba.h b/sys/security/mac_biba/mac_biba.h
new file mode 100644
index 0000000..05eefab
--- /dev/null
+++ b/sys/security/mac_biba/mac_biba.h
@@ -0,0 +1,97 @@
+/*-
+ * Copyright (c) 1999-2002 Robert N. M. Watson
+ * Copyright (c) 2001-2004 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * This software was developed by Robert Watson for the TrustedBSD Project.
+ *
+ * This software was developed for the FreeBSD Project in part by Network
+ * Associates Laboratories, the Security Research Division of Network
+ * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"),
+ * as part of the DARPA CHATS research program.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+/*
+ * Definitions for the TrustedBSD Biba integrity policy module.
+ */
+#ifndef _SYS_SECURITY_MAC_BIBA_H
+#define _SYS_SECURITY_MAC_BIBA_H
+
+#define MAC_BIBA_EXTATTR_NAMESPACE EXTATTR_NAMESPACE_SYSTEM
+#define MAC_BIBA_EXTATTR_NAME "mac_biba"
+
+#define MAC_BIBA_LABEL_NAME "biba"
+
+#define MAC_BIBA_FLAG_EFFECTIVE 0x00000001 /* mb_effective initialized */
+#define MAC_BIBA_FLAG_RANGE 0x00000002 /* mb_range* initialized */
+#define MAC_BIBA_FLAGS_BOTH (MAC_BIBA_FLAG_EFFECTIVE | MAC_BIBA_FLAG_RANGE)
+
+#define MAC_BIBA_TYPE_UNDEF 0 /* Undefined */
+#define MAC_BIBA_TYPE_GRADE 1 /* Hierarchal grade with mb_grade. */
+#define MAC_BIBA_TYPE_LOW 2 /* Dominated by any
+ * MAC_BIBA_TYPE_LABEL. */
+#define MAC_BIBA_TYPE_HIGH 3 /* Dominates any
+ * MAC_BIBA_TYPE_LABEL. */
+#define MAC_BIBA_TYPE_EQUAL 4 /* Equivilent to any
+ * MAC_BIBA_TYPE_LABEL. */
+
+/*
+ * Structures and constants associated with a Biba Integrity policy.
+ * mac_biba represents a Biba label, with mb_type determining its properties,
+ * and mb_grade represents the hierarchal grade if valid for the current
+ * mb_type.
+ */
+
+#define MAC_BIBA_MAX_COMPARTMENTS 256
+
+struct mac_biba_element {
+ u_short mbe_type;
+ u_short mbe_grade;
+ u_char mbe_compartments[MAC_BIBA_MAX_COMPARTMENTS >> 3];
+};
+
+/*
+ * Biba labels consist of two components: an effective label, and a label
+ * range. Depending on the context, one or both may be used; the mb_flags
+ * field permits the provider to indicate what fields are intended for
+ * use.
+ */
+struct mac_biba {
+ int mb_flags;
+ struct mac_biba_element mb_effective;
+ struct mac_biba_element mb_rangelow, mb_rangehigh;
+};
+
+/*
+ * Biba compartments bit test/set macros.
+ * The range is 1 to MAC_BIBA_MAX_COMPARTMENTS.
+ */
+#define MAC_BIBA_BIT_TEST(b, w) \
+ ((w)[(((b) - 1) >> 3)] & (1 << (((b) - 1) & 7)))
+#define MAC_BIBA_BIT_SET(b, w) \
+ ((w)[(((b) - 1) >> 3)] |= (1 << (((b) - 1) & 7)))
+#define MAC_BIBA_BIT_SET_EMPTY(set) biba_bit_set_empty(set)
+
+#endif /* !_SYS_SECURITY_MAC_BIBA_H */
diff --git a/sys/security/mac_bsdextended/mac_bsdextended.c b/sys/security/mac_bsdextended/mac_bsdextended.c
new file mode 100644
index 0000000..b30b214
--- /dev/null
+++ b/sys/security/mac_bsdextended/mac_bsdextended.c
@@ -0,0 +1,526 @@
+/*-
+ * Copyright (c) 1999-2002, 2007-2008 Robert N. M. Watson
+ * Copyright (c) 2001-2005 Networks Associates Technology, Inc.
+ * Copyright (c) 2005 Tom Rhodes
+ * Copyright (c) 2006 SPARTA, Inc.
+ * All rights reserved.
+ *
+ * This software was developed by Robert Watson for the TrustedBSD Project.
+ * It was later enhanced by Tom Rhodes for the TrustedBSD Project.
+ *
+ * This software was developed for the FreeBSD Project in part by Network
+ * Associates Laboratories, the Security Research Division of Network
+ * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"),
+ * as part of the DARPA CHATS research program.
+ *
+ * This software was enhanced by SPARTA ISSO under SPAWAR contract
+ * N66001-04-C-6019 ("SEFOS").
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Developed by the TrustedBSD Project.
+ *
+ * "BSD Extended" MAC policy, allowing the administrator to impose mandatory
+ * firewall-like rules regarding users and file system objects.
+ */
+
+#include <sys/param.h>
+#include <sys/acl.h>
+#include <sys/kernel.h>
+#include <sys/jail.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/mount.h>
+#include <sys/mutex.h>
+#include <sys/priv.h>
+#include <sys/proc.h>
+#include <sys/systm.h>
+#include <sys/vnode.h>
+#include <sys/sysctl.h>
+#include <sys/syslog.h>
+#include <sys/stat.h>
+
+#include <security/mac/mac_policy.h>
+#include <security/mac_bsdextended/mac_bsdextended.h>
+#include <security/mac_bsdextended/ugidfw_internal.h>
+
+static struct mtx ugidfw_mtx;
+
+SYSCTL_DECL(_security_mac);
+
+SYSCTL_NODE(_security_mac, OID_AUTO, bsdextended, CTLFLAG_RW, 0,
+ "TrustedBSD extended BSD MAC policy controls");
+
+static int ugidfw_enabled = 1;
+SYSCTL_INT(_security_mac_bsdextended, OID_AUTO, enabled, CTLFLAG_RW,
+ &ugidfw_enabled, 0, "Enforce extended BSD policy");
+TUNABLE_INT("security.mac.bsdextended.enabled", &ugidfw_enabled);
+
+MALLOC_DEFINE(M_MACBSDEXTENDED, "mac_bsdextended", "BSD Extended MAC rule");
+
+#define MAC_BSDEXTENDED_MAXRULES 250
+static struct mac_bsdextended_rule *rules[MAC_BSDEXTENDED_MAXRULES];
+static int rule_count = 0;
+static int rule_slots = 0;
+static int rule_version = MB_VERSION;
+
+SYSCTL_INT(_security_mac_bsdextended, OID_AUTO, rule_count, CTLFLAG_RD,
+ &rule_count, 0, "Number of defined rules\n");
+SYSCTL_INT(_security_mac_bsdextended, OID_AUTO, rule_slots, CTLFLAG_RD,
+ &rule_slots, 0, "Number of used rule slots\n");
+SYSCTL_INT(_security_mac_bsdextended, OID_AUTO, rule_version, CTLFLAG_RD,
+ &rule_version, 0, "Version number for API\n");
+
+/*
+ * This is just used for logging purposes, eventually we would like to log
+ * much more then failed requests.
+ */
+static int ugidfw_logging;
+SYSCTL_INT(_security_mac_bsdextended, OID_AUTO, logging, CTLFLAG_RW,
+ &ugidfw_logging, 0, "Log failed authorization requests");
+
+/*
+ * This tunable is here for compatibility. It will allow the user to switch
+ * between the new mode (first rule matches) and the old functionality (all
+ * rules match).
+ */
+static int ugidfw_firstmatch_enabled;
+SYSCTL_INT(_security_mac_bsdextended, OID_AUTO, firstmatch_enabled,
+ CTLFLAG_RW, &ugidfw_firstmatch_enabled, 1,
+ "Disable/enable match first rule functionality");
+
+static int
+ugidfw_rule_valid(struct mac_bsdextended_rule *rule)
+{
+
+ if ((rule->mbr_subject.mbs_flags | MBS_ALL_FLAGS) != MBS_ALL_FLAGS)
+ return (EINVAL);
+ if ((rule->mbr_subject.mbs_neg | MBS_ALL_FLAGS) != MBS_ALL_FLAGS)
+ return (EINVAL);
+ if ((rule->mbr_object.mbo_flags | MBO_ALL_FLAGS) != MBO_ALL_FLAGS)
+ return (EINVAL);
+ if ((rule->mbr_object.mbo_neg | MBO_ALL_FLAGS) != MBO_ALL_FLAGS)
+ return (EINVAL);
+ if ((rule->mbr_object.mbo_neg | MBO_TYPE_DEFINED) &&
+ (rule->mbr_object.mbo_type | MBO_ALL_TYPE) != MBO_ALL_TYPE)
+ return (EINVAL);
+ if ((rule->mbr_mode | MBI_ALLPERM) != MBI_ALLPERM)
+ return (EINVAL);
+ return (0);
+}
+
+static int
+sysctl_rule(SYSCTL_HANDLER_ARGS)
+{
+ struct mac_bsdextended_rule temprule, *ruleptr;
+ u_int namelen;
+ int error, index, *name;
+
+ error = 0;
+ name = (int *)arg1;
+ namelen = arg2;
+ if (namelen != 1)
+ return (EINVAL);
+ index = name[0];
+ if (index >= MAC_BSDEXTENDED_MAXRULES)
+ return (ENOENT);
+
+ ruleptr = NULL;
+ if (req->newptr && req->newlen != 0) {
+ error = SYSCTL_IN(req, &temprule, sizeof(temprule));
+ if (error)
+ return (error);
+ ruleptr = malloc(sizeof(*ruleptr), M_MACBSDEXTENDED,
+ M_WAITOK | M_ZERO);
+ }
+
+ mtx_lock(&ugidfw_mtx);
+ if (req->oldptr) {
+ if (index < 0 || index > rule_slots + 1) {
+ error = ENOENT;
+ goto out;
+ }
+ if (rules[index] == NULL) {
+ error = ENOENT;
+ goto out;
+ }
+ temprule = *rules[index];
+ }
+ if (req->newptr && req->newlen == 0) {
+ KASSERT(ruleptr == NULL, ("sysctl_rule: ruleptr != NULL"));
+ ruleptr = rules[index];
+ if (ruleptr == NULL) {
+ error = ENOENT;
+ goto out;
+ }
+ rule_count--;
+ rules[index] = NULL;
+ } else if (req->newptr) {
+ error = ugidfw_rule_valid(&temprule);
+ if (error)
+ goto out;
+ if (rules[index] == NULL) {
+ *ruleptr = temprule;
+ rules[index] = ruleptr;
+ ruleptr = NULL;
+ if (index + 1 > rule_slots)
+ rule_slots = index + 1;
+ rule_count++;
+ } else
+ *rules[index] = temprule;
+ }
+out:
+ mtx_unlock(&ugidfw_mtx);
+ if (ruleptr != NULL)
+ free(ruleptr, M_MACBSDEXTENDED);
+ if (req->oldptr && error == 0)
+ error = SYSCTL_OUT(req, &temprule, sizeof(temprule));
+ return (error);
+}
+
+SYSCTL_NODE(_security_mac_bsdextended, OID_AUTO, rules, CTLFLAG_RW,
+ sysctl_rule, "BSD extended MAC rules");
+
+static void
+ugidfw_init(struct mac_policy_conf *mpc)
+{
+
+ mtx_init(&ugidfw_mtx, "mac_bsdextended lock", NULL, MTX_DEF);
+}
+
+static void
+ugidfw_destroy(struct mac_policy_conf *mpc)
+{
+ int i;
+
+ for (i = 0; i < MAC_BSDEXTENDED_MAXRULES; i++) {
+ if (rules[i] != NULL)
+ free(rules[i], M_MACBSDEXTENDED);
+ }
+ mtx_destroy(&ugidfw_mtx);
+}
+
+static int
+ugidfw_rulecheck(struct mac_bsdextended_rule *rule,
+ struct ucred *cred, struct vnode *vp, struct vattr *vap, int acc_mode)
+{
+ int mac_granted, match, priv_granted;
+ int i;
+
+ /*
+ * Is there a subject match?
+ */
+ mtx_assert(&ugidfw_mtx, MA_OWNED);
+ if (rule->mbr_subject.mbs_flags & MBS_UID_DEFINED) {
+ match = ((cred->cr_uid <= rule->mbr_subject.mbs_uid_max &&
+ cred->cr_uid >= rule->mbr_subject.mbs_uid_min) ||
+ (cred->cr_ruid <= rule->mbr_subject.mbs_uid_max &&
+ cred->cr_ruid >= rule->mbr_subject.mbs_uid_min) ||
+ (cred->cr_svuid <= rule->mbr_subject.mbs_uid_max &&
+ cred->cr_svuid >= rule->mbr_subject.mbs_uid_min));
+ if (rule->mbr_subject.mbs_neg & MBS_UID_DEFINED)
+ match = !match;
+ if (!match)
+ return (0);
+ }
+
+ if (rule->mbr_subject.mbs_flags & MBS_GID_DEFINED) {
+ match = ((cred->cr_rgid <= rule->mbr_subject.mbs_gid_max &&
+ cred->cr_rgid >= rule->mbr_subject.mbs_gid_min) ||
+ (cred->cr_svgid <= rule->mbr_subject.mbs_gid_max &&
+ cred->cr_svgid >= rule->mbr_subject.mbs_gid_min));
+ if (!match) {
+ for (i = 0; i < cred->cr_ngroups; i++) {
+ if (cred->cr_groups[i]
+ <= rule->mbr_subject.mbs_gid_max &&
+ cred->cr_groups[i]
+ >= rule->mbr_subject.mbs_gid_min) {
+ match = 1;
+ break;
+ }
+ }
+ }
+ if (rule->mbr_subject.mbs_neg & MBS_GID_DEFINED)
+ match = !match;
+ if (!match)
+ return (0);
+ }
+
+ if (rule->mbr_subject.mbs_flags & MBS_PRISON_DEFINED) {
+ match = (cred->cr_prison != NULL &&
+ cred->cr_prison->pr_id == rule->mbr_subject.mbs_prison);
+ if (rule->mbr_subject.mbs_neg & MBS_PRISON_DEFINED)
+ match = !match;
+ if (!match)
+ return (0);
+ }
+
+ /*
+ * Is there an object match?
+ */
+ if (rule->mbr_object.mbo_flags & MBO_UID_DEFINED) {
+ match = (vap->va_uid <= rule->mbr_object.mbo_uid_max &&
+ vap->va_uid >= rule->mbr_object.mbo_uid_min);
+ if (rule->mbr_object.mbo_neg & MBO_UID_DEFINED)
+ match = !match;
+ if (!match)
+ return (0);
+ }
+
+ if (rule->mbr_object.mbo_flags & MBO_GID_DEFINED) {
+ match = (vap->va_gid <= rule->mbr_object.mbo_gid_max &&
+ vap->va_gid >= rule->mbr_object.mbo_gid_min);
+ if (rule->mbr_object.mbo_neg & MBO_GID_DEFINED)
+ match = !match;
+ if (!match)
+ return (0);
+ }
+
+ if (rule->mbr_object.mbo_flags & MBO_FSID_DEFINED) {
+ match = (bcmp(&(vp->v_mount->mnt_stat.f_fsid),
+ &(rule->mbr_object.mbo_fsid),
+ sizeof(rule->mbr_object.mbo_fsid)) == 0);
+ if (rule->mbr_object.mbo_neg & MBO_FSID_DEFINED)
+ match = !match;
+ if (!match)
+ return (0);
+ }
+
+ if (rule->mbr_object.mbo_flags & MBO_SUID) {
+ match = (vap->va_mode & S_ISUID);
+ if (rule->mbr_object.mbo_neg & MBO_SUID)
+ match = !match;
+ if (!match)
+ return (0);
+ }
+
+ if (rule->mbr_object.mbo_flags & MBO_SGID) {
+ match = (vap->va_mode & S_ISGID);
+ if (rule->mbr_object.mbo_neg & MBO_SGID)
+ match = !match;
+ if (!match)
+ return (0);
+ }
+
+ if (rule->mbr_object.mbo_flags & MBO_UID_SUBJECT) {
+ match = (vap->va_uid == cred->cr_uid ||
+ vap->va_uid == cred->cr_ruid ||
+ vap->va_uid == cred->cr_svuid);
+ if (rule->mbr_object.mbo_neg & MBO_UID_SUBJECT)
+ match = !match;
+ if (!match)
+ return (0);
+ }
+
+ if (rule->mbr_object.mbo_flags & MBO_GID_SUBJECT) {
+ match = (groupmember(vap->va_gid, cred) ||
+ vap->va_gid == cred->cr_rgid ||
+ vap->va_gid == cred->cr_svgid);
+ if (rule->mbr_object.mbo_neg & MBO_GID_SUBJECT)
+ match = !match;
+ if (!match)
+ return (0);
+ }
+
+ if (rule->mbr_object.mbo_flags & MBO_TYPE_DEFINED) {
+ switch (vap->va_type) {
+ case VREG:
+ match = (rule->mbr_object.mbo_type & MBO_TYPE_REG);
+ break;
+ case VDIR:
+ match = (rule->mbr_object.mbo_type & MBO_TYPE_DIR);
+ break;
+ case VBLK:
+ match = (rule->mbr_object.mbo_type & MBO_TYPE_BLK);
+ break;
+ case VCHR:
+ match = (rule->mbr_object.mbo_type & MBO_TYPE_CHR);
+ break;
+ case VLNK:
+ match = (rule->mbr_object.mbo_type & MBO_TYPE_LNK);
+ break;
+ case VSOCK:
+ match = (rule->mbr_object.mbo_type & MBO_TYPE_SOCK);
+ break;
+ case VFIFO:
+ match = (rule->mbr_object.mbo_type & MBO_TYPE_FIFO);
+ break;
+ default:
+ match = 0;
+ }
+ if (rule->mbr_object.mbo_neg & MBO_TYPE_DEFINED)
+ match = !match;
+ if (!match)
+ return (0);
+ }
+
+ /*
+ * MBI_APPEND should not be here as it should get converted to
+ * MBI_WRITE.
+ */
+ priv_granted = 0;
+ mac_granted = rule->mbr_mode;
+ if ((acc_mode & MBI_ADMIN) && (mac_granted & MBI_ADMIN) == 0 &&
+ priv_check_cred(cred, PRIV_VFS_ADMIN, 0) == 0)
+ priv_granted |= MBI_ADMIN;
+ if ((acc_mode & MBI_EXEC) && (mac_granted & MBI_EXEC) == 0 &&
+ priv_check_cred(cred, (vap->va_type == VDIR) ? PRIV_VFS_LOOKUP :
+ PRIV_VFS_EXEC, 0) == 0)
+ priv_granted |= MBI_EXEC;
+ if ((acc_mode & MBI_READ) && (mac_granted & MBI_READ) == 0 &&
+ priv_check_cred(cred, PRIV_VFS_READ, 0) == 0)
+ priv_granted |= MBI_READ;
+ if ((acc_mode & MBI_STAT) && (mac_granted & MBI_STAT) == 0 &&
+ priv_check_cred(cred, PRIV_VFS_STAT, 0) == 0)
+ priv_granted |= MBI_STAT;
+ if ((acc_mode & MBI_WRITE) && (mac_granted & MBI_WRITE) == 0 &&
+ priv_check_cred(cred, PRIV_VFS_WRITE, 0) == 0)
+ priv_granted |= MBI_WRITE;
+ /*
+ * Is the access permitted?
+ */
+ if (((mac_granted | priv_granted) & acc_mode) != acc_mode) {
+ if (ugidfw_logging)
+ log(LOG_AUTHPRIV, "mac_bsdextended: %d:%d request %d"
+ " on %d:%d failed. \n", cred->cr_ruid,
+ cred->cr_rgid, acc_mode, vap->va_uid,
+ vap->va_gid);
+ return (EACCES);
+ }
+
+ /*
+ * If the rule matched, permits access, and first match is enabled,
+ * return success.
+ */
+ if (ugidfw_firstmatch_enabled)
+ return (EJUSTRETURN);
+ else
+ return (0);
+}
+
+int
+ugidfw_check(struct ucred *cred, struct vnode *vp, struct vattr *vap,
+ int acc_mode)
+{
+ int error, i;
+
+ /*
+ * Since we do not separately handle append, map append to write.
+ */
+ if (acc_mode & MBI_APPEND) {
+ acc_mode &= ~MBI_APPEND;
+ acc_mode |= MBI_WRITE;
+ }
+ mtx_lock(&ugidfw_mtx);
+ for (i = 0; i < rule_slots; i++) {
+ if (rules[i] == NULL)
+ continue;
+ error = ugidfw_rulecheck(rules[i], cred,
+ vp, vap, acc_mode);
+ if (error == EJUSTRETURN)
+ break;
+ if (error) {
+ mtx_unlock(&ugidfw_mtx);
+ return (error);
+ }
+ }
+ mtx_unlock(&ugidfw_mtx);
+ return (0);
+}
+
+int
+ugidfw_check_vp(struct ucred *cred, struct vnode *vp, int acc_mode)
+{
+ int error;
+ struct vattr vap;
+
+ if (!ugidfw_enabled)
+ return (0);
+ error = VOP_GETATTR(vp, &vap, cred);
+ if (error)
+ return (error);
+ return (ugidfw_check(cred, vp, &vap, acc_mode));
+}
+
+int
+ugidfw_accmode2mbi(accmode_t accmode)
+{
+ int mbi;
+
+ mbi = 0;
+ if (accmode & VEXEC)
+ mbi |= MBI_EXEC;
+ if (accmode & VWRITE)
+ mbi |= MBI_WRITE;
+ if (accmode & VREAD)
+ mbi |= MBI_READ;
+ if (accmode & VADMIN)
+ mbi |= MBI_ADMIN;
+ if (accmode & VSTAT)
+ mbi |= MBI_STAT;
+ if (accmode & VAPPEND)
+ mbi |= MBI_APPEND;
+ return (mbi);
+}
+
+static struct mac_policy_ops ugidfw_ops =
+{
+ .mpo_destroy = ugidfw_destroy,
+ .mpo_init = ugidfw_init,
+ .mpo_system_check_acct = ugidfw_system_check_acct,
+ .mpo_system_check_auditctl = ugidfw_system_check_auditctl,
+ .mpo_system_check_swapon = ugidfw_system_check_swapon,
+ .mpo_vnode_check_access = ugidfw_vnode_check_access,
+ .mpo_vnode_check_chdir = ugidfw_vnode_check_chdir,
+ .mpo_vnode_check_chroot = ugidfw_vnode_check_chroot,
+ .mpo_vnode_check_create = ugidfw_check_create_vnode,
+ .mpo_vnode_check_deleteacl = ugidfw_vnode_check_deleteacl,
+ .mpo_vnode_check_deleteextattr = ugidfw_vnode_check_deleteextattr,
+ .mpo_vnode_check_exec = ugidfw_vnode_check_exec,
+ .mpo_vnode_check_getacl = ugidfw_vnode_check_getacl,
+ .mpo_vnode_check_getextattr = ugidfw_vnode_check_getextattr,
+ .mpo_vnode_check_link = ugidfw_vnode_check_link,
+ .mpo_vnode_check_listextattr = ugidfw_vnode_check_listextattr,
+ .mpo_vnode_check_lookup = ugidfw_vnode_check_lookup,
+ .mpo_vnode_check_open = ugidfw_vnode_check_open,
+ .mpo_vnode_check_readdir = ugidfw_vnode_check_readdir,
+ .mpo_vnode_check_readlink = ugidfw_vnode_check_readdlink,
+ .mpo_vnode_check_rename_from = ugidfw_vnode_check_rename_from,
+ .mpo_vnode_check_rename_to = ugidfw_vnode_check_rename_to,
+ .mpo_vnode_check_revoke = ugidfw_vnode_check_revoke,
+ .mpo_vnode_check_setacl = ugidfw_check_setacl_vnode,
+ .mpo_vnode_check_setextattr = ugidfw_vnode_check_setextattr,
+ .mpo_vnode_check_setflags = ugidfw_vnode_check_setflags,
+ .mpo_vnode_check_setmode = ugidfw_vnode_check_setmode,
+ .mpo_vnode_check_setowner = ugidfw_vnode_check_setowner,
+ .mpo_vnode_check_setutimes = ugidfw_vnode_check_setutimes,
+ .mpo_vnode_check_stat = ugidfw_vnode_check_stat,
+ .mpo_vnode_check_unlink = ugidfw_vnode_check_unlink,
+};
+
+MAC_POLICY_SET(&ugidfw_ops, mac_bsdextended, "TrustedBSD MAC/BSD Extended",
+ MPC_LOADTIME_FLAG_UNLOADOK, NULL, 0);
diff --git a/sys/security/mac_bsdextended/mac_bsdextended.h b/sys/security/mac_bsdextended/mac_bsdextended.h
new file mode 100644
index 0000000..c09abc0
--- /dev/null
+++ b/sys/security/mac_bsdextended/mac_bsdextended.h
@@ -0,0 +1,114 @@
+/*-
+ * Copyright (c) 1999-2002 Robert N. M. Watson
+ * Copyright (c) 2001-2004 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * This software was developed by Robert Watson for the TrustedBSD Project.
+ *
+ * This software was developed for the FreeBSD Project in part by Network
+ * Associates Laboratories, the Security Research Division of Network
+ * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"),
+ * as part of the DARPA CHATS research program.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _SYS_SECURITY_MAC_BSDEXTENDED_H
+#define _SYS_SECURITY_MAC_BSDEXTENDED_H
+
+#define MB_VERSION 2 /* Used to check library and kernel are the same. */
+
+/*
+ * Rights that can be represented in mbr_mode. These have the same values as
+ * the V* rights in vnode.h, but in order to avoid sharing user and kernel
+ * constants, we define them here. That will also improve ABI stability if
+ * the in-kernel values change.
+ */
+#define MBI_EXEC 000100
+#define MBI_WRITE 000200
+#define MBI_READ 000400
+#define MBI_ADMIN 010000
+#define MBI_STAT 020000
+#define MBI_APPEND 040000
+#define MBI_ALLPERM (MBI_EXEC | MBI_WRITE | MBI_READ | MBI_ADMIN | \
+ MBI_STAT | MBI_APPEND)
+
+#define MBS_UID_DEFINED 0x00000001 /* uid field should be matched */
+#define MBS_GID_DEFINED 0x00000002 /* gid field should be matched */
+#define MBS_PRISON_DEFINED 0x00000004 /* prison field should be matched */
+
+#define MBS_ALL_FLAGS (MBS_UID_DEFINED | MBS_GID_DEFINED | MBS_PRISON_DEFINED)
+
+struct mac_bsdextended_subject {
+ int mbs_flags;
+ int mbs_neg;
+ uid_t mbs_uid_min;
+ uid_t mbs_uid_max;
+ gid_t mbs_gid_min;
+ gid_t mbs_gid_max;
+ int mbs_prison;
+};
+
+#define MBO_UID_DEFINED 0x00000001 /* uid field should be matched */
+#define MBO_GID_DEFINED 0x00000002 /* gid field should be matched */
+#define MBO_FSID_DEFINED 0x00000004 /* fsid field should be matched */
+#define MBO_SUID 0x00000008 /* object must be suid */
+#define MBO_SGID 0x00000010 /* object must be sgid */
+#define MBO_UID_SUBJECT 0x00000020 /* uid must match subject */
+#define MBO_GID_SUBJECT 0x00000040 /* gid must match subject */
+#define MBO_TYPE_DEFINED 0x00000080 /* object type should be matched */
+
+#define MBO_ALL_FLAGS (MBO_UID_DEFINED | MBO_GID_DEFINED | MBO_FSID_DEFINED | \
+ MBO_SUID | MBO_SGID | MBO_UID_SUBJECT | MBO_GID_SUBJECT | \
+ MBO_TYPE_DEFINED)
+
+#define MBO_TYPE_REG 0x00000001
+#define MBO_TYPE_DIR 0x00000002
+#define MBO_TYPE_BLK 0x00000004
+#define MBO_TYPE_CHR 0x00000008
+#define MBO_TYPE_LNK 0x00000010
+#define MBO_TYPE_SOCK 0x00000020
+#define MBO_TYPE_FIFO 0x00000040
+
+#define MBO_ALL_TYPE (MBO_TYPE_REG | MBO_TYPE_DIR | MBO_TYPE_BLK | \
+ MBO_TYPE_CHR | MBO_TYPE_LNK | MBO_TYPE_SOCK | MBO_TYPE_FIFO)
+
+struct mac_bsdextended_object {
+ int mbo_flags;
+ int mbo_neg;
+ uid_t mbo_uid_min;
+ uid_t mbo_uid_max;
+ gid_t mbo_gid_min;
+ gid_t mbo_gid_max;
+ struct fsid mbo_fsid;
+ int mbo_type;
+};
+
+struct mac_bsdextended_rule {
+ struct mac_bsdextended_subject mbr_subject;
+ struct mac_bsdextended_object mbr_object;
+ mode_t mbr_mode; /* maximum access */
+};
+
+#endif /* _SYS_SECURITY_MAC_BSDEXTENDED_H */
diff --git a/sys/security/mac_bsdextended/ugidfw_internal.h b/sys/security/mac_bsdextended/ugidfw_internal.h
new file mode 100644
index 0000000..c53326d
--- /dev/null
+++ b/sys/security/mac_bsdextended/ugidfw_internal.h
@@ -0,0 +1,118 @@
+/*-
+ * Copyright (c) 2008 Robert N. M. Watson
+ * All rights reserved.
+ *
+ * This software was developed by Robert Watson for the TrustedBSD Project.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _SYS_SECURITY_MAC_BSDEXTENDED_UGIDFW_INTERNAL_H
+#define _SYS_SECURITY_MAC_BSDEXTENDED_UGIDFW_INTERNAL_H
+
+/*
+ * Central access control routines used by object-specific checks.
+ */
+int ugidfw_accmode2mbi(accmode_t accmode);
+int ugidfw_check(struct ucred *cred, struct vnode *vp, struct vattr *vap,
+ int acc_mode);
+int ugidfw_check_vp(struct ucred *cred, struct vnode *vp, int acc_mode);
+
+/*
+ * System access control checks.
+ */
+int ugidfw_system_check_acct(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel);
+int ugidfw_system_check_auditctl(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel);
+int ugidfw_system_check_swapon(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel);
+
+/*
+ * Vnode access control checks.
+ */
+int ugidfw_vnode_check_access(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, accmode_t accmode);
+int ugidfw_vnode_check_chdir(struct ucred *cred, struct vnode *dvp,
+ struct label *dvplabel);
+int ugidfw_vnode_check_chroot(struct ucred *cred, struct vnode *dvp,
+ struct label *dvplabel);
+int ugidfw_check_create_vnode(struct ucred *cred, struct vnode *dvp,
+ struct label *dvplabel, struct componentname *cnp,
+ struct vattr *vap);
+int ugidfw_vnode_check_deleteacl(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, acl_type_t type);
+int ugidfw_vnode_check_deleteextattr(struct ucred *cred,
+ struct vnode *vp, struct label *vplabel, int attrnamespace,
+ const char *name);
+int ugidfw_vnode_check_exec(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, struct image_params *imgp,
+ struct label *execlabel);
+int ugidfw_vnode_check_getacl(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, acl_type_t type);
+int ugidfw_vnode_check_getextattr(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, int attrnamespace, const char *name,
+ struct uio *uio);
+int ugidfw_vnode_check_link(struct ucred *cred, struct vnode *dvp,
+ struct label *dvplabel, struct vnode *vp, struct label *label,
+ struct componentname *cnp);
+int ugidfw_vnode_check_listextattr(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, int attrnamespace);
+int ugidfw_vnode_check_lookup(struct ucred *cred, struct vnode *dvp,
+ struct label *dvplabel, struct componentname *cnp);
+int ugidfw_vnode_check_open(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, accmode_t accmode);
+int ugidfw_vnode_check_readdir(struct ucred *cred, struct vnode *dvp,
+ struct label *dvplabel);
+int ugidfw_vnode_check_readdlink(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel);
+int ugidfw_vnode_check_rename_from(struct ucred *cred, struct vnode *dvp,
+ struct label *dvplabel, struct vnode *vp, struct label *vplabel,
+ struct componentname *cnp);
+int ugidfw_vnode_check_rename_to(struct ucred *cred, struct vnode *dvp,
+ struct label *dvplabel, struct vnode *vp, struct label *vplabel,
+ int samedir, struct componentname *cnp);
+int ugidfw_vnode_check_revoke(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel);
+int ugidfw_check_setacl_vnode(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, acl_type_t type, struct acl *acl);
+int ugidfw_vnode_check_setextattr(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, int attrnamespace, const char *name,
+ struct uio *uio);
+int ugidfw_vnode_check_setflags(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, u_long flags);
+int ugidfw_vnode_check_setmode(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, mode_t mode);
+int ugidfw_vnode_check_setowner(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, uid_t uid, gid_t gid);
+int ugidfw_vnode_check_setutimes(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, struct timespec atime,
+ struct timespec utime);
+int ugidfw_vnode_check_stat(struct ucred *active_cred,
+ struct ucred *file_cred, struct vnode *vp, struct label *vplabel);
+int ugidfw_vnode_check_unlink(struct ucred *cred, struct vnode *dvp,
+ struct label *dvplabel, struct vnode *vp, struct label *vplabel,
+ struct componentname *cnp);
+
+#endif /* _SYS_SECURITY_MAC_BSDEXTENDED_UGIDFW_INTERNAL_H */
diff --git a/sys/security/mac_bsdextended/ugidfw_system.c b/sys/security/mac_bsdextended/ugidfw_system.c
new file mode 100644
index 0000000..49e4f1d
--- /dev/null
+++ b/sys/security/mac_bsdextended/ugidfw_system.c
@@ -0,0 +1,91 @@
+/*-
+ * Copyright (c) 1999-2002, 2007 Robert N. M. Watson
+ * Copyright (c) 2001-2005 Networks Associates Technology, Inc.
+ * Copyright (c) 2005 Tom Rhodes
+ * Copyright (c) 2006 SPARTA, Inc.
+ * All rights reserved.
+ *
+ * This software was developed by Robert Watson for the TrustedBSD Project.
+ * It was later enhanced by Tom Rhodes for the TrustedBSD Project.
+ *
+ * This software was developed for the FreeBSD Project in part by Network
+ * Associates Laboratories, the Security Research Division of Network
+ * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"),
+ * as part of the DARPA CHATS research program.
+ *
+ * This software was enhanced by SPARTA ISSO under SPAWAR contract
+ * N66001-04-C-6019 ("SEFOS").
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/param.h>
+#include <sys/acl.h>
+#include <sys/kernel.h>
+#include <sys/jail.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/mount.h>
+#include <sys/mutex.h>
+#include <sys/priv.h>
+#include <sys/systm.h>
+#include <sys/vnode.h>
+#include <sys/sysctl.h>
+#include <sys/syslog.h>
+#include <sys/stat.h>
+
+#include <security/mac/mac_policy.h>
+#include <security/mac_bsdextended/mac_bsdextended.h>
+#include <security/mac_bsdextended/ugidfw_internal.h>
+
+int
+ugidfw_system_check_acct(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel)
+{
+
+ if (vp != NULL)
+ return (ugidfw_check_vp(cred, vp, MBI_WRITE));
+ else
+ return (0);
+}
+
+int
+ugidfw_system_check_auditctl(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel)
+{
+
+ if (vp != NULL)
+ return (ugidfw_check_vp(cred, vp, MBI_WRITE));
+ else
+ return (0);
+}
+
+int
+ugidfw_system_check_swapon(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel)
+{
+
+ return (ugidfw_check_vp(cred, vp, MBI_WRITE));
+}
diff --git a/sys/security/mac_bsdextended/ugidfw_vnode.c b/sys/security/mac_bsdextended/ugidfw_vnode.c
new file mode 100644
index 0000000..bfcc5ac
--- /dev/null
+++ b/sys/security/mac_bsdextended/ugidfw_vnode.c
@@ -0,0 +1,297 @@
+/*-
+ * Copyright (c) 1999-2002, 2007-2008 Robert N. M. Watson
+ * Copyright (c) 2001-2005 Networks Associates Technology, Inc.
+ * Copyright (c) 2005 Tom Rhodes
+ * Copyright (c) 2006 SPARTA, Inc.
+ * All rights reserved.
+ *
+ * This software was developed by Robert Watson for the TrustedBSD Project.
+ * It was later enhanced by Tom Rhodes for the TrustedBSD Project.
+ *
+ * This software was developed for the FreeBSD Project in part by Network
+ * Associates Laboratories, the Security Research Division of Network
+ * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"),
+ * as part of the DARPA CHATS research program.
+ *
+ * This software was enhanced by SPARTA ISSO under SPAWAR contract
+ * N66001-04-C-6019 ("SEFOS").
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/param.h>
+#include <sys/acl.h>
+#include <sys/kernel.h>
+#include <sys/jail.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/mount.h>
+#include <sys/mutex.h>
+#include <sys/priv.h>
+#include <sys/systm.h>
+#include <sys/vnode.h>
+#include <sys/sysctl.h>
+#include <sys/syslog.h>
+#include <sys/stat.h>
+
+#include <security/mac/mac_policy.h>
+#include <security/mac_bsdextended/mac_bsdextended.h>
+#include <security/mac_bsdextended/ugidfw_internal.h>
+
+int
+ugidfw_vnode_check_access(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, accmode_t accmode)
+{
+
+ return (ugidfw_check_vp(cred, vp, ugidfw_accmode2mbi(accmode)));
+}
+
+int
+ugidfw_vnode_check_chdir(struct ucred *cred, struct vnode *dvp,
+ struct label *dvplabel)
+{
+
+ return (ugidfw_check_vp(cred, dvp, MBI_EXEC));
+}
+
+int
+ugidfw_vnode_check_chroot(struct ucred *cred, struct vnode *dvp,
+ struct label *dvplabel)
+{
+
+ return (ugidfw_check_vp(cred, dvp, MBI_EXEC));
+}
+
+int
+ugidfw_check_create_vnode(struct ucred *cred, struct vnode *dvp,
+ struct label *dvplabel, struct componentname *cnp, struct vattr *vap)
+{
+
+ return (ugidfw_check_vp(cred, dvp, MBI_WRITE));
+}
+
+int
+ugidfw_vnode_check_deleteacl(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, acl_type_t type)
+{
+
+ return (ugidfw_check_vp(cred, vp, MBI_ADMIN));
+}
+
+int
+ugidfw_vnode_check_deleteextattr(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, int attrnamespace, const char *name)
+{
+
+ return (ugidfw_check_vp(cred, vp, MBI_WRITE));
+}
+
+int
+ugidfw_vnode_check_exec(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, struct image_params *imgp,
+ struct label *execlabel)
+{
+
+ return (ugidfw_check_vp(cred, vp, MBI_READ|MBI_EXEC));
+}
+
+int
+ugidfw_vnode_check_getacl(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, acl_type_t type)
+{
+
+ return (ugidfw_check_vp(cred, vp, MBI_STAT));
+}
+
+int
+ugidfw_vnode_check_getextattr(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, int attrnamespace, const char *name,
+ struct uio *uio)
+{
+
+ return (ugidfw_check_vp(cred, vp, MBI_READ));
+}
+
+int
+ugidfw_vnode_check_link(struct ucred *cred, struct vnode *dvp,
+ struct label *dvplabel, struct vnode *vp, struct label *label,
+ struct componentname *cnp)
+{
+ int error;
+
+ error = ugidfw_check_vp(cred, dvp, MBI_WRITE);
+ if (error)
+ return (error);
+ error = ugidfw_check_vp(cred, vp, MBI_WRITE);
+ if (error)
+ return (error);
+ return (0);
+}
+
+int
+ugidfw_vnode_check_listextattr(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, int attrnamespace)
+{
+
+ return (ugidfw_check_vp(cred, vp, MBI_READ));
+}
+
+int
+ugidfw_vnode_check_lookup(struct ucred *cred, struct vnode *dvp,
+ struct label *dvplabel, struct componentname *cnp)
+{
+
+ return (ugidfw_check_vp(cred, dvp, MBI_EXEC));
+}
+
+int
+ugidfw_vnode_check_open(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, accmode_t accmode)
+{
+
+ return (ugidfw_check_vp(cred, vp, ugidfw_accmode2mbi(accmode)));
+}
+
+int
+ugidfw_vnode_check_readdir(struct ucred *cred, struct vnode *dvp,
+ struct label *dvplabel)
+{
+
+ return (ugidfw_check_vp(cred, dvp, MBI_READ));
+}
+
+int
+ugidfw_vnode_check_readdlink(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel)
+{
+
+ return (ugidfw_check_vp(cred, vp, MBI_READ));
+}
+
+int
+ugidfw_vnode_check_rename_from(struct ucred *cred, struct vnode *dvp,
+ struct label *dvplabel, struct vnode *vp, struct label *vplabel,
+ struct componentname *cnp)
+{
+ int error;
+
+ error = ugidfw_check_vp(cred, dvp, MBI_WRITE);
+ if (error)
+ return (error);
+ return (ugidfw_check_vp(cred, vp, MBI_WRITE));
+}
+
+int
+ugidfw_vnode_check_rename_to(struct ucred *cred, struct vnode *dvp,
+ struct label *dvplabel, struct vnode *vp, struct label *vplabel,
+ int samedir, struct componentname *cnp)
+{
+ int error;
+
+ error = ugidfw_check_vp(cred, dvp, MBI_WRITE);
+ if (error)
+ return (error);
+ if (vp != NULL)
+ error = ugidfw_check_vp(cred, vp, MBI_WRITE);
+ return (error);
+}
+
+int
+ugidfw_vnode_check_revoke(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel)
+{
+
+ return (ugidfw_check_vp(cred, vp, MBI_ADMIN));
+}
+
+int
+ugidfw_check_setacl_vnode(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, acl_type_t type, struct acl *acl)
+{
+
+ return (ugidfw_check_vp(cred, vp, MBI_ADMIN));
+}
+
+int
+ugidfw_vnode_check_setextattr(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, int attrnamespace, const char *name,
+ struct uio *uio)
+{
+
+ return (ugidfw_check_vp(cred, vp, MBI_WRITE));
+}
+
+int
+ugidfw_vnode_check_setflags(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, u_long flags)
+{
+
+ return (ugidfw_check_vp(cred, vp, MBI_ADMIN));
+}
+
+int
+ugidfw_vnode_check_setmode(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, mode_t mode)
+{
+
+ return (ugidfw_check_vp(cred, vp, MBI_ADMIN));
+}
+
+int
+ugidfw_vnode_check_setowner(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, uid_t uid, gid_t gid)
+{
+
+ return (ugidfw_check_vp(cred, vp, MBI_ADMIN));
+}
+
+int
+ugidfw_vnode_check_setutimes(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, struct timespec atime, struct timespec utime)
+{
+
+ return (ugidfw_check_vp(cred, vp, MBI_ADMIN));
+}
+
+int
+ugidfw_vnode_check_stat(struct ucred *active_cred,
+ struct ucred *file_cred, struct vnode *vp, struct label *vplabel)
+{
+
+ return (ugidfw_check_vp(active_cred, vp, MBI_STAT));
+}
+
+int
+ugidfw_vnode_check_unlink(struct ucred *cred, struct vnode *dvp,
+ struct label *dvplabel, struct vnode *vp, struct label *vplabel,
+ struct componentname *cnp)
+{
+ int error;
+
+ error = ugidfw_check_vp(cred, dvp, MBI_WRITE);
+ if (error)
+ return (error);
+ return (ugidfw_check_vp(cred, vp, MBI_WRITE));
+}
diff --git a/sys/security/mac_ifoff/mac_ifoff.c b/sys/security/mac_ifoff/mac_ifoff.c
new file mode 100644
index 0000000..8543d2b
--- /dev/null
+++ b/sys/security/mac_ifoff/mac_ifoff.c
@@ -0,0 +1,173 @@
+/*-
+ * Copyright (c) 1999-2002, 2007 Robert N. M. Watson
+ * Copyright (c) 2001-2002 Networks Associates Technology, Inc.
+ * Copyright (c) 2006 SPARTA, Inc.
+ * All rights reserved.
+ *
+ * This software was developed by Robert Watson for the TrustedBSD Project.
+ *
+ * This software was developed for the FreeBSD Project in part by Network
+ * Associates Laboratories, the Security Research Division of Network
+ * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"),
+ * as part of the DARPA CHATS research program.
+ *
+ * This software was enhanced by SPARTA ISSO under SPAWAR contract
+ * N66001-04-C-6019 ("SEFOS").
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Developed by the TrustedBSD Project.
+ *
+ * Limit access to interfaces until they are specifically administratively
+ * enabled. Prevents protocol stack-driven packet leakage in unsafe
+ * environments.
+ */
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+
+#include <net/bpfdesc.h>
+#include <net/if_types.h>
+
+#include <security/mac/mac_policy.h>
+
+SYSCTL_DECL(_security_mac);
+
+SYSCTL_NODE(_security_mac, OID_AUTO, ifoff, CTLFLAG_RW, 0,
+ "TrustedBSD mac_ifoff policy controls");
+
+static int ifoff_enabled = 1;
+SYSCTL_INT(_security_mac_ifoff, OID_AUTO, enabled, CTLFLAG_RW,
+ &ifoff_enabled, 0, "Enforce ifoff policy");
+TUNABLE_INT("security.mac.ifoff.enabled", &ifoff_enabled);
+
+static int ifoff_lo_enabled = 1;
+SYSCTL_INT(_security_mac_ifoff, OID_AUTO, lo_enabled, CTLFLAG_RW,
+ &ifoff_lo_enabled, 0, "Enable loopback interfaces");
+TUNABLE_INT("security.mac.ifoff.lo_enabled", &ifoff_lo_enabled);
+
+static int ifoff_other_enabled = 0;
+SYSCTL_INT(_security_mac_ifoff, OID_AUTO, other_enabled, CTLFLAG_RW,
+ &ifoff_other_enabled, 0, "Enable other interfaces");
+TUNABLE_INT("security.mac.ifoff.other_enabled", &ifoff_other_enabled);
+
+static int ifoff_bpfrecv_enabled = 0;
+SYSCTL_INT(_security_mac_ifoff, OID_AUTO, bpfrecv_enabled, CTLFLAG_RW,
+ &ifoff_bpfrecv_enabled, 0, "Enable BPF reception even when interface "
+ "is disabled");
+TUNABLE_INT("security.mac.ifoff.bpfrecv.enabled", &ifoff_bpfrecv_enabled);
+
+static int
+ifnet_check_outgoing(struct ifnet *ifp)
+{
+
+ if (!ifoff_enabled)
+ return (0);
+
+ if (ifoff_lo_enabled && ifp->if_type == IFT_LOOP)
+ return (0);
+
+ if (ifoff_other_enabled && ifp->if_type != IFT_LOOP)
+ return (0);
+
+ return (EPERM);
+}
+
+static int
+ifnet_check_incoming(struct ifnet *ifp, int viabpf)
+{
+ if (!ifoff_enabled)
+ return (0);
+
+ if (ifoff_lo_enabled && ifp->if_type == IFT_LOOP)
+ return (0);
+
+ if (ifoff_other_enabled && ifp->if_type != IFT_LOOP)
+ return (0);
+
+ if (viabpf && ifoff_bpfrecv_enabled)
+ return (0);
+
+ return (EPERM);
+}
+
+/*
+ * Object-specific entry point implementations are sorted alphabetically by
+ * object type and then by operation.
+ */
+static int
+ifoff_bpfdesc_check_receive(struct bpf_d *d, struct label *dlabel,
+ struct ifnet *ifp, struct label *ifplabel)
+{
+
+ return (ifnet_check_incoming(ifp, 1));
+}
+
+static int
+ifoff_ifnet_check_transmit(struct ifnet *ifp, struct label *ifplabel,
+ struct mbuf *m, struct label *mlabel)
+{
+
+ return (ifnet_check_outgoing(ifp));
+}
+
+static int
+ifoff_inpcb_check_deliver(struct inpcb *inp, struct label *inplabel,
+ struct mbuf *m, struct label *mlabel)
+{
+
+ M_ASSERTPKTHDR(m);
+ if (m->m_pkthdr.rcvif != NULL)
+ return (ifnet_check_incoming(m->m_pkthdr.rcvif, 0));
+
+ return (0);
+}
+
+static int
+ifoff_socket_check_deliver(struct socket *so, struct label *solabel,
+ struct mbuf *m, struct label *mlabel)
+{
+
+ M_ASSERTPKTHDR(m);
+ if (m->m_pkthdr.rcvif != NULL)
+ return (ifnet_check_incoming(m->m_pkthdr.rcvif, 0));
+
+ return (0);
+}
+
+static struct mac_policy_ops ifoff_ops =
+{
+ .mpo_bpfdesc_check_receive = ifoff_bpfdesc_check_receive,
+ .mpo_ifnet_check_transmit = ifoff_ifnet_check_transmit,
+ .mpo_inpcb_check_deliver = ifoff_inpcb_check_deliver,
+ .mpo_socket_check_deliver = ifoff_socket_check_deliver,
+};
+
+MAC_POLICY_SET(&ifoff_ops, mac_ifoff, "TrustedBSD MAC/ifoff",
+ MPC_LOADTIME_FLAG_UNLOADOK, NULL, 0);
diff --git a/sys/security/mac_lomac/mac_lomac.c b/sys/security/mac_lomac/mac_lomac.c
new file mode 100644
index 0000000..9eb2701
--- /dev/null
+++ b/sys/security/mac_lomac/mac_lomac.c
@@ -0,0 +1,3076 @@
+/*-
+ * Copyright (c) 1999-2002, 2007-2008 Robert N. M. Watson
+ * Copyright (c) 2001-2005 Networks Associates Technology, Inc.
+ * Copyright (c) 2006 SPARTA, Inc.
+ * All rights reserved.
+ *
+ * This software was developed by Robert Watson for the TrustedBSD Project.
+ *
+ * This software was developed for the FreeBSD Project in part by NAI Labs,
+ * the Security Research Division of Network Associates, Inc. under
+ * DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA
+ * CHATS research program.
+ *
+ * This software was enhanced by SPARTA ISSO under SPAWAR contract
+ * N66001-04-C-6019 ("SEFOS").
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Developed by the TrustedBSD Project.
+ *
+ * Low-watermark floating label mandatory integrity policy.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/acl.h>
+#include <sys/conf.h>
+#include <sys/extattr.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/mman.h>
+#include <sys/mount.h>
+#include <sys/priv.h>
+#include <sys/proc.h>
+#include <sys/sbuf.h>
+#include <sys/systm.h>
+#include <sys/sysproto.h>
+#include <sys/sysent.h>
+#include <sys/systm.h>
+#include <sys/vnode.h>
+#include <sys/file.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/sx.h>
+#include <sys/pipe.h>
+#include <sys/sysctl.h>
+#include <sys/syslog.h>
+
+#include <fs/devfs/devfs.h>
+
+#include <net/bpfdesc.h>
+#include <net/if.h>
+#include <net/if_types.h>
+#include <net/if_var.h>
+
+#include <netinet/in.h>
+#include <netinet/in_pcb.h>
+#include <netinet/ip_var.h>
+
+#include <vm/vm.h>
+
+#include <security/mac/mac_policy.h>
+#include <security/mac/mac_framework.h>
+#include <security/mac_lomac/mac_lomac.h>
+
+struct mac_lomac_proc {
+ struct mac_lomac mac_lomac;
+ struct mtx mtx;
+};
+
+SYSCTL_DECL(_security_mac);
+
+SYSCTL_NODE(_security_mac, OID_AUTO, lomac, CTLFLAG_RW, 0,
+ "TrustedBSD mac_lomac policy controls");
+
+static int lomac_label_size = sizeof(struct mac_lomac);
+SYSCTL_INT(_security_mac_lomac, OID_AUTO, label_size, CTLFLAG_RD,
+ &lomac_label_size, 0, "Size of struct mac_lomac");
+
+static int lomac_enabled = 1;
+SYSCTL_INT(_security_mac_lomac, OID_AUTO, enabled, CTLFLAG_RW,
+ &lomac_enabled, 0, "Enforce MAC/LOMAC policy");
+TUNABLE_INT("security.mac.lomac.enabled", &lomac_enabled);
+
+static int destroyed_not_inited;
+SYSCTL_INT(_security_mac_lomac, OID_AUTO, destroyed_not_inited, CTLFLAG_RD,
+ &destroyed_not_inited, 0, "Count of labels destroyed but not inited");
+
+static int trust_all_interfaces = 0;
+SYSCTL_INT(_security_mac_lomac, OID_AUTO, trust_all_interfaces, CTLFLAG_RD,
+ &trust_all_interfaces, 0, "Consider all interfaces 'trusted' by MAC/LOMAC");
+TUNABLE_INT("security.mac.lomac.trust_all_interfaces", &trust_all_interfaces);
+
+static char trusted_interfaces[128];
+SYSCTL_STRING(_security_mac_lomac, OID_AUTO, trusted_interfaces, CTLFLAG_RD,
+ trusted_interfaces, 0, "Interfaces considered 'trusted' by MAC/LOMAC");
+TUNABLE_STR("security.mac.lomac.trusted_interfaces", trusted_interfaces,
+ sizeof(trusted_interfaces));
+
+static int ptys_equal = 0;
+SYSCTL_INT(_security_mac_lomac, OID_AUTO, ptys_equal, CTLFLAG_RW,
+ &ptys_equal, 0, "Label pty devices as lomac/equal on create");
+TUNABLE_INT("security.mac.lomac.ptys_equal", &ptys_equal);
+
+static int revocation_enabled = 1;
+SYSCTL_INT(_security_mac_lomac, OID_AUTO, revocation_enabled, CTLFLAG_RW,
+ &revocation_enabled, 0, "Revoke access to objects on relabel");
+TUNABLE_INT("security.mac.lomac.revocation_enabled", &revocation_enabled);
+
+static int lomac_slot;
+#define SLOT(l) ((struct mac_lomac *)mac_label_get((l), lomac_slot))
+#define SLOT_SET(l, val) mac_label_set((l), lomac_slot, (uintptr_t)(val))
+#define PSLOT(l) ((struct mac_lomac_proc *) \
+ mac_label_get((l), lomac_slot))
+#define PSLOT_SET(l, val) mac_label_set((l), lomac_slot, (uintptr_t)(val))
+
+MALLOC_DEFINE(M_LOMAC, "mac_lomac_label", "MAC/LOMAC labels");
+
+static struct mac_lomac *
+lomac_alloc(int flag)
+{
+ struct mac_lomac *ml;
+
+ ml = malloc(sizeof(*ml), M_LOMAC, M_ZERO | flag);
+
+ return (ml);
+}
+
+static void
+lomac_free(struct mac_lomac *ml)
+{
+
+ if (ml != NULL)
+ free(ml, M_LOMAC);
+ else
+ atomic_add_int(&destroyed_not_inited, 1);
+}
+
+static int
+lomac_atmostflags(struct mac_lomac *ml, int flags)
+{
+
+ if ((ml->ml_flags & flags) != ml->ml_flags)
+ return (EINVAL);
+ return (0);
+}
+
+static int
+lomac_dominate_element(struct mac_lomac_element *a,
+ struct mac_lomac_element *b)
+{
+
+ switch (a->mle_type) {
+ case MAC_LOMAC_TYPE_EQUAL:
+ case MAC_LOMAC_TYPE_HIGH:
+ return (1);
+
+ case MAC_LOMAC_TYPE_LOW:
+ switch (b->mle_type) {
+ case MAC_LOMAC_TYPE_GRADE:
+ case MAC_LOMAC_TYPE_HIGH:
+ return (0);
+
+ case MAC_LOMAC_TYPE_EQUAL:
+ case MAC_LOMAC_TYPE_LOW:
+ return (1);
+
+ default:
+ panic("lomac_dominate_element: b->mle_type invalid");
+ }
+
+ case MAC_LOMAC_TYPE_GRADE:
+ switch (b->mle_type) {
+ case MAC_LOMAC_TYPE_EQUAL:
+ case MAC_LOMAC_TYPE_LOW:
+ return (1);
+
+ case MAC_LOMAC_TYPE_HIGH:
+ return (0);
+
+ case MAC_LOMAC_TYPE_GRADE:
+ return (a->mle_grade >= b->mle_grade);
+
+ default:
+ panic("lomac_dominate_element: b->mle_type invalid");
+ }
+
+ default:
+ panic("lomac_dominate_element: a->mle_type invalid");
+ }
+}
+
+static int
+lomac_range_in_range(struct mac_lomac *rangea, struct mac_lomac *rangeb)
+{
+
+ return (lomac_dominate_element(&rangeb->ml_rangehigh,
+ &rangea->ml_rangehigh) &&
+ lomac_dominate_element(&rangea->ml_rangelow,
+ &rangeb->ml_rangelow));
+}
+
+static int
+lomac_single_in_range(struct mac_lomac *single, struct mac_lomac *range)
+{
+
+ KASSERT((single->ml_flags & MAC_LOMAC_FLAG_SINGLE) != 0,
+ ("lomac_single_in_range: a not single"));
+ KASSERT((range->ml_flags & MAC_LOMAC_FLAG_RANGE) != 0,
+ ("lomac_single_in_range: b not range"));
+
+ return (lomac_dominate_element(&range->ml_rangehigh,
+ &single->ml_single) && lomac_dominate_element(&single->ml_single,
+ &range->ml_rangelow));
+}
+
+static int
+lomac_auxsingle_in_range(struct mac_lomac *single, struct mac_lomac *range)
+{
+
+ KASSERT((single->ml_flags & MAC_LOMAC_FLAG_AUX) != 0,
+ ("lomac_single_in_range: a not auxsingle"));
+ KASSERT((range->ml_flags & MAC_LOMAC_FLAG_RANGE) != 0,
+ ("lomac_single_in_range: b not range"));
+
+ return (lomac_dominate_element(&range->ml_rangehigh,
+ &single->ml_auxsingle) &&
+ lomac_dominate_element(&single->ml_auxsingle,
+ &range->ml_rangelow));
+}
+
+static int
+lomac_dominate_single(struct mac_lomac *a, struct mac_lomac *b)
+{
+ KASSERT((a->ml_flags & MAC_LOMAC_FLAG_SINGLE) != 0,
+ ("lomac_dominate_single: a not single"));
+ KASSERT((b->ml_flags & MAC_LOMAC_FLAG_SINGLE) != 0,
+ ("lomac_dominate_single: b not single"));
+
+ return (lomac_dominate_element(&a->ml_single, &b->ml_single));
+}
+
+static int
+lomac_subject_dominate(struct mac_lomac *a, struct mac_lomac *b)
+{
+ KASSERT((~a->ml_flags &
+ (MAC_LOMAC_FLAG_SINGLE | MAC_LOMAC_FLAG_RANGE)) == 0,
+ ("lomac_dominate_single: a not subject"));
+ KASSERT((b->ml_flags & MAC_LOMAC_FLAG_SINGLE) != 0,
+ ("lomac_dominate_single: b not single"));
+
+ return (lomac_dominate_element(&a->ml_rangehigh, &b->ml_single));
+}
+
+static int
+lomac_equal_element(struct mac_lomac_element *a, struct mac_lomac_element *b)
+{
+
+ if (a->mle_type == MAC_LOMAC_TYPE_EQUAL ||
+ b->mle_type == MAC_LOMAC_TYPE_EQUAL)
+ return (1);
+
+ return (a->mle_type == b->mle_type && a->mle_grade == b->mle_grade);
+}
+
+static int
+lomac_equal_single(struct mac_lomac *a, struct mac_lomac *b)
+{
+
+ KASSERT((a->ml_flags & MAC_LOMAC_FLAG_SINGLE) != 0,
+ ("lomac_equal_single: a not single"));
+ KASSERT((b->ml_flags & MAC_LOMAC_FLAG_SINGLE) != 0,
+ ("lomac_equal_single: b not single"));
+
+ return (lomac_equal_element(&a->ml_single, &b->ml_single));
+}
+
+static int
+lomac_contains_equal(struct mac_lomac *ml)
+{
+
+ if (ml->ml_flags & MAC_LOMAC_FLAG_SINGLE)
+ if (ml->ml_single.mle_type == MAC_LOMAC_TYPE_EQUAL)
+ return (1);
+ if (ml->ml_flags & MAC_LOMAC_FLAG_AUX)
+ if (ml->ml_auxsingle.mle_type == MAC_LOMAC_TYPE_EQUAL)
+ return (1);
+
+ if (ml->ml_flags & MAC_LOMAC_FLAG_RANGE) {
+ if (ml->ml_rangelow.mle_type == MAC_LOMAC_TYPE_EQUAL)
+ return (1);
+ if (ml->ml_rangehigh.mle_type == MAC_LOMAC_TYPE_EQUAL)
+ return (1);
+ }
+
+ return (0);
+}
+
+static int
+lomac_subject_privileged(struct mac_lomac *ml)
+{
+
+ KASSERT((ml->ml_flags & MAC_LOMAC_FLAGS_BOTH) ==
+ MAC_LOMAC_FLAGS_BOTH,
+ ("lomac_subject_privileged: subject doesn't have both labels"));
+
+ /* If the single is EQUAL, it's ok. */
+ if (ml->ml_single.mle_type == MAC_LOMAC_TYPE_EQUAL)
+ return (0);
+
+ /* If either range endpoint is EQUAL, it's ok. */
+ if (ml->ml_rangelow.mle_type == MAC_LOMAC_TYPE_EQUAL ||
+ ml->ml_rangehigh.mle_type == MAC_LOMAC_TYPE_EQUAL)
+ return (0);
+
+ /* If the range is low-high, it's ok. */
+ if (ml->ml_rangelow.mle_type == MAC_LOMAC_TYPE_LOW &&
+ ml->ml_rangehigh.mle_type == MAC_LOMAC_TYPE_HIGH)
+ return (0);
+
+ /* It's not ok. */
+ return (EPERM);
+}
+
+static int
+lomac_high_single(struct mac_lomac *ml)
+{
+
+ KASSERT((ml->ml_flags & MAC_LOMAC_FLAG_SINGLE) != 0,
+ ("lomac_high_single: mac_lomac not single"));
+
+ return (ml->ml_single.mle_type == MAC_LOMAC_TYPE_HIGH);
+}
+
+static int
+lomac_valid(struct mac_lomac *ml)
+{
+
+ if (ml->ml_flags & MAC_LOMAC_FLAG_SINGLE) {
+ switch (ml->ml_single.mle_type) {
+ case MAC_LOMAC_TYPE_GRADE:
+ case MAC_LOMAC_TYPE_EQUAL:
+ case MAC_LOMAC_TYPE_HIGH:
+ case MAC_LOMAC_TYPE_LOW:
+ break;
+
+ default:
+ return (EINVAL);
+ }
+ } else {
+ if (ml->ml_single.mle_type != MAC_LOMAC_TYPE_UNDEF)
+ return (EINVAL);
+ }
+
+ if (ml->ml_flags & MAC_LOMAC_FLAG_AUX) {
+ switch (ml->ml_auxsingle.mle_type) {
+ case MAC_LOMAC_TYPE_GRADE:
+ case MAC_LOMAC_TYPE_EQUAL:
+ case MAC_LOMAC_TYPE_HIGH:
+ case MAC_LOMAC_TYPE_LOW:
+ break;
+
+ default:
+ return (EINVAL);
+ }
+ } else {
+ if (ml->ml_auxsingle.mle_type != MAC_LOMAC_TYPE_UNDEF)
+ return (EINVAL);
+ }
+
+ if (ml->ml_flags & MAC_LOMAC_FLAG_RANGE) {
+ switch (ml->ml_rangelow.mle_type) {
+ case MAC_LOMAC_TYPE_GRADE:
+ case MAC_LOMAC_TYPE_EQUAL:
+ case MAC_LOMAC_TYPE_HIGH:
+ case MAC_LOMAC_TYPE_LOW:
+ break;
+
+ default:
+ return (EINVAL);
+ }
+
+ switch (ml->ml_rangehigh.mle_type) {
+ case MAC_LOMAC_TYPE_GRADE:
+ case MAC_LOMAC_TYPE_EQUAL:
+ case MAC_LOMAC_TYPE_HIGH:
+ case MAC_LOMAC_TYPE_LOW:
+ break;
+
+ default:
+ return (EINVAL);
+ }
+ if (!lomac_dominate_element(&ml->ml_rangehigh,
+ &ml->ml_rangelow))
+ return (EINVAL);
+ } else {
+ if (ml->ml_rangelow.mle_type != MAC_LOMAC_TYPE_UNDEF ||
+ ml->ml_rangehigh.mle_type != MAC_LOMAC_TYPE_UNDEF)
+ return (EINVAL);
+ }
+
+ return (0);
+}
+
+static void
+lomac_set_range(struct mac_lomac *ml, u_short typelow, u_short gradelow,
+ u_short typehigh, u_short gradehigh)
+{
+
+ ml->ml_rangelow.mle_type = typelow;
+ ml->ml_rangelow.mle_grade = gradelow;
+ ml->ml_rangehigh.mle_type = typehigh;
+ ml->ml_rangehigh.mle_grade = gradehigh;
+ ml->ml_flags |= MAC_LOMAC_FLAG_RANGE;
+}
+
+static void
+lomac_set_single(struct mac_lomac *ml, u_short type, u_short grade)
+{
+
+ ml->ml_single.mle_type = type;
+ ml->ml_single.mle_grade = grade;
+ ml->ml_flags |= MAC_LOMAC_FLAG_SINGLE;
+}
+
+static void
+lomac_copy_range(struct mac_lomac *labelfrom, struct mac_lomac *labelto)
+{
+
+ KASSERT((labelfrom->ml_flags & MAC_LOMAC_FLAG_RANGE) != 0,
+ ("lomac_copy_range: labelfrom not range"));
+
+ labelto->ml_rangelow = labelfrom->ml_rangelow;
+ labelto->ml_rangehigh = labelfrom->ml_rangehigh;
+ labelto->ml_flags |= MAC_LOMAC_FLAG_RANGE;
+}
+
+static void
+lomac_copy_single(struct mac_lomac *labelfrom, struct mac_lomac *labelto)
+{
+
+ KASSERT((labelfrom->ml_flags & MAC_LOMAC_FLAG_SINGLE) != 0,
+ ("lomac_copy_single: labelfrom not single"));
+
+ labelto->ml_single = labelfrom->ml_single;
+ labelto->ml_flags |= MAC_LOMAC_FLAG_SINGLE;
+}
+
+static void
+lomac_copy_auxsingle(struct mac_lomac *labelfrom, struct mac_lomac *labelto)
+{
+
+ KASSERT((labelfrom->ml_flags & MAC_LOMAC_FLAG_AUX) != 0,
+ ("lomac_copy_auxsingle: labelfrom not auxsingle"));
+
+ labelto->ml_auxsingle = labelfrom->ml_auxsingle;
+ labelto->ml_flags |= MAC_LOMAC_FLAG_AUX;
+}
+
+static void
+lomac_copy(struct mac_lomac *source, struct mac_lomac *dest)
+{
+
+ if (source->ml_flags & MAC_LOMAC_FLAG_SINGLE)
+ lomac_copy_single(source, dest);
+ if (source->ml_flags & MAC_LOMAC_FLAG_AUX)
+ lomac_copy_auxsingle(source, dest);
+ if (source->ml_flags & MAC_LOMAC_FLAG_RANGE)
+ lomac_copy_range(source, dest);
+}
+
+static int lomac_to_string(struct sbuf *sb, struct mac_lomac *ml);
+
+static int
+maybe_demote(struct mac_lomac *subjlabel, struct mac_lomac *objlabel,
+ const char *actionname, const char *objname, struct vnode *vp)
+{
+ struct sbuf subjlabel_sb, subjtext_sb, objlabel_sb;
+ char *subjlabeltext, *objlabeltext, *subjtext;
+ struct mac_lomac cached_subjlabel;
+ struct mac_lomac_proc *subj;
+ struct vattr va;
+ struct proc *p;
+ pid_t pgid;
+
+ subj = PSLOT(curthread->td_proc->p_label);
+
+ p = curthread->td_proc;
+ mtx_lock(&subj->mtx);
+ if (subj->mac_lomac.ml_flags & MAC_LOMAC_FLAG_UPDATE) {
+ /*
+ * Check to see if the pending demotion would be more or less
+ * severe than this one, and keep the more severe. This can
+ * only happen for a multi-threaded application.
+ */
+ if (lomac_dominate_single(objlabel, &subj->mac_lomac)) {
+ mtx_unlock(&subj->mtx);
+ return (0);
+ }
+ }
+ bzero(&subj->mac_lomac, sizeof(subj->mac_lomac));
+ /*
+ * Always demote the single label.
+ */
+ lomac_copy_single(objlabel, &subj->mac_lomac);
+ /*
+ * Start with the original range, then minimize each side of the
+ * range to the point of not dominating the object. The high side
+ * will always be demoted, of course.
+ */
+ lomac_copy_range(subjlabel, &subj->mac_lomac);
+ if (!lomac_dominate_element(&objlabel->ml_single,
+ &subj->mac_lomac.ml_rangelow))
+ subj->mac_lomac.ml_rangelow = objlabel->ml_single;
+ subj->mac_lomac.ml_rangehigh = objlabel->ml_single;
+ subj->mac_lomac.ml_flags |= MAC_LOMAC_FLAG_UPDATE;
+ thread_lock(curthread);
+ curthread->td_flags |= TDF_ASTPENDING | TDF_MACPEND;
+ thread_unlock(curthread);
+
+ /*
+ * Avoid memory allocation while holding a mutex; cache the label.
+ */
+ lomac_copy_single(&subj->mac_lomac, &cached_subjlabel);
+ mtx_unlock(&subj->mtx);
+
+ sbuf_new(&subjlabel_sb, NULL, 0, SBUF_AUTOEXTEND);
+ lomac_to_string(&subjlabel_sb, subjlabel);
+ sbuf_finish(&subjlabel_sb);
+ subjlabeltext = sbuf_data(&subjlabel_sb);
+
+ sbuf_new(&subjtext_sb, NULL, 0, SBUF_AUTOEXTEND);
+ lomac_to_string(&subjtext_sb, &subj->mac_lomac);
+ sbuf_finish(&subjtext_sb);
+ subjtext = sbuf_data(&subjtext_sb);
+
+ sbuf_new(&objlabel_sb, NULL, 0, SBUF_AUTOEXTEND);
+ lomac_to_string(&objlabel_sb, objlabel);
+ sbuf_finish(&objlabel_sb);
+ objlabeltext = sbuf_data(&objlabel_sb);
+
+ pgid = p->p_pgrp->pg_id; /* XXX could be stale? */
+ if (vp != NULL && VOP_GETATTR(vp, &va, curthread->td_ucred) == 0) {
+ log(LOG_INFO, "LOMAC: level-%s subject p%dg%du%d:%s demoted to"
+ " level %s after %s a level-%s %s (inode=%ld, "
+ "mountpount=%s)\n",
+ subjlabeltext, p->p_pid, pgid, curthread->td_ucred->cr_uid,
+ p->p_comm, subjtext, actionname, objlabeltext, objname,
+ va.va_fileid, vp->v_mount->mnt_stat.f_mntonname);
+ } else {
+ log(LOG_INFO, "LOMAC: level-%s subject p%dg%du%d:%s demoted to"
+ " level %s after %s a level-%s %s\n",
+ subjlabeltext, p->p_pid, pgid, curthread->td_ucred->cr_uid,
+ p->p_comm, subjtext, actionname, objlabeltext, objname);
+ }
+
+ sbuf_delete(&subjlabel_sb);
+ sbuf_delete(&subjtext_sb);
+ sbuf_delete(&objlabel_sb);
+
+ return (0);
+}
+
+/*
+ * Relabel "to" to "from" only if "from" is a valid label (contains at least
+ * a single), as for a relabel operation which may or may not involve a
+ * relevant label.
+ */
+static void
+try_relabel(struct mac_lomac *from, struct mac_lomac *to)
+{
+
+ if (from->ml_flags & MAC_LOMAC_FLAG_SINGLE) {
+ bzero(to, sizeof(*to));
+ lomac_copy(from, to);
+ }
+}
+
+/*
+ * Policy module operations.
+ */
+static void
+lomac_init(struct mac_policy_conf *conf)
+{
+
+}
+
+/*
+ * Label operations.
+ */
+static void
+lomac_init_label(struct label *label)
+{
+
+ SLOT_SET(label, lomac_alloc(M_WAITOK));
+}
+
+static int
+lomac_init_label_waitcheck(struct label *label, int flag)
+{
+
+ SLOT_SET(label, lomac_alloc(flag));
+ if (SLOT(label) == NULL)
+ return (ENOMEM);
+
+ return (0);
+}
+
+static void
+lomac_destroy_label(struct label *label)
+{
+
+ lomac_free(SLOT(label));
+ SLOT_SET(label, NULL);
+}
+
+static int
+lomac_element_to_string(struct sbuf *sb, struct mac_lomac_element *element)
+{
+
+ switch (element->mle_type) {
+ case MAC_LOMAC_TYPE_HIGH:
+ return (sbuf_printf(sb, "high"));
+
+ case MAC_LOMAC_TYPE_LOW:
+ return (sbuf_printf(sb, "low"));
+
+ case MAC_LOMAC_TYPE_EQUAL:
+ return (sbuf_printf(sb, "equal"));
+
+ case MAC_LOMAC_TYPE_GRADE:
+ return (sbuf_printf(sb, "%d", element->mle_grade));
+
+ default:
+ panic("lomac_element_to_string: invalid type (%d)",
+ element->mle_type);
+ }
+}
+
+static int
+lomac_to_string(struct sbuf *sb, struct mac_lomac *ml)
+{
+
+ if (ml->ml_flags & MAC_LOMAC_FLAG_SINGLE) {
+ if (lomac_element_to_string(sb, &ml->ml_single) == -1)
+ return (EINVAL);
+ }
+
+ if (ml->ml_flags & MAC_LOMAC_FLAG_AUX) {
+ if (sbuf_putc(sb, '[') == -1)
+ return (EINVAL);
+
+ if (lomac_element_to_string(sb, &ml->ml_auxsingle) == -1)
+ return (EINVAL);
+
+ if (sbuf_putc(sb, ']') == -1)
+ return (EINVAL);
+ }
+
+ if (ml->ml_flags & MAC_LOMAC_FLAG_RANGE) {
+ if (sbuf_putc(sb, '(') == -1)
+ return (EINVAL);
+
+ if (lomac_element_to_string(sb, &ml->ml_rangelow) == -1)
+ return (EINVAL);
+
+ if (sbuf_putc(sb, '-') == -1)
+ return (EINVAL);
+
+ if (lomac_element_to_string(sb, &ml->ml_rangehigh) == -1)
+ return (EINVAL);
+
+ if (sbuf_putc(sb, ')') == -1)
+ return (EINVAL);
+ }
+
+ return (0);
+}
+
+static int
+lomac_externalize_label(struct label *label, char *element_name,
+ struct sbuf *sb, int *claimed)
+{
+ struct mac_lomac *ml;
+
+ if (strcmp(MAC_LOMAC_LABEL_NAME, element_name) != 0)
+ return (0);
+
+ (*claimed)++;
+
+ ml = SLOT(label);
+
+ return (lomac_to_string(sb, ml));
+}
+
+static int
+lomac_parse_element(struct mac_lomac_element *element, char *string)
+{
+
+ if (strcmp(string, "high") == 0 || strcmp(string, "hi") == 0) {
+ element->mle_type = MAC_LOMAC_TYPE_HIGH;
+ element->mle_grade = MAC_LOMAC_TYPE_UNDEF;
+ } else if (strcmp(string, "low") == 0 || strcmp(string, "lo") == 0) {
+ element->mle_type = MAC_LOMAC_TYPE_LOW;
+ element->mle_grade = MAC_LOMAC_TYPE_UNDEF;
+ } else if (strcmp(string, "equal") == 0 ||
+ strcmp(string, "eq") == 0) {
+ element->mle_type = MAC_LOMAC_TYPE_EQUAL;
+ element->mle_grade = MAC_LOMAC_TYPE_UNDEF;
+ } else {
+ char *p0, *p1;
+ int d;
+
+ p0 = string;
+ d = strtol(p0, &p1, 10);
+
+ if (d < 0 || d > 65535)
+ return (EINVAL);
+ element->mle_type = MAC_LOMAC_TYPE_GRADE;
+ element->mle_grade = d;
+
+ if (p1 == p0 || *p1 != '\0')
+ return (EINVAL);
+ }
+
+ return (0);
+}
+
+/*
+ * Note: destructively consumes the string, make a local copy before calling
+ * if that's a problem.
+ */
+static int
+lomac_parse(struct mac_lomac *ml, char *string)
+{
+ char *range, *rangeend, *rangehigh, *rangelow, *single, *auxsingle,
+ *auxsingleend;
+ int error;
+
+ /* Do we have a range? */
+ single = string;
+ range = index(string, '(');
+ if (range == single)
+ single = NULL;
+ auxsingle = index(string, '[');
+ if (auxsingle == single)
+ single = NULL;
+ if (range != NULL && auxsingle != NULL)
+ return (EINVAL);
+ rangelow = rangehigh = NULL;
+ if (range != NULL) {
+ /* Nul terminate the end of the single string. */
+ *range = '\0';
+ range++;
+ rangelow = range;
+ rangehigh = index(rangelow, '-');
+ if (rangehigh == NULL)
+ return (EINVAL);
+ rangehigh++;
+ if (*rangelow == '\0' || *rangehigh == '\0')
+ return (EINVAL);
+ rangeend = index(rangehigh, ')');
+ if (rangeend == NULL)
+ return (EINVAL);
+ if (*(rangeend + 1) != '\0')
+ return (EINVAL);
+ /* Nul terminate the ends of the ranges. */
+ *(rangehigh - 1) = '\0';
+ *rangeend = '\0';
+ }
+ KASSERT((rangelow != NULL && rangehigh != NULL) ||
+ (rangelow == NULL && rangehigh == NULL),
+ ("lomac_internalize_label: range mismatch"));
+ if (auxsingle != NULL) {
+ /* Nul terminate the end of the single string. */
+ *auxsingle = '\0';
+ auxsingle++;
+ auxsingleend = index(auxsingle, ']');
+ if (auxsingleend == NULL)
+ return (EINVAL);
+ if (*(auxsingleend + 1) != '\0')
+ return (EINVAL);
+ /* Nul terminate the end of the auxsingle. */
+ *auxsingleend = '\0';
+ }
+
+ bzero(ml, sizeof(*ml));
+ if (single != NULL) {
+ error = lomac_parse_element(&ml->ml_single, single);
+ if (error)
+ return (error);
+ ml->ml_flags |= MAC_LOMAC_FLAG_SINGLE;
+ }
+
+ if (auxsingle != NULL) {
+ error = lomac_parse_element(&ml->ml_auxsingle, auxsingle);
+ if (error)
+ return (error);
+ ml->ml_flags |= MAC_LOMAC_FLAG_AUX;
+ }
+
+ if (rangelow != NULL) {
+ error = lomac_parse_element(&ml->ml_rangelow, rangelow);
+ if (error)
+ return (error);
+ error = lomac_parse_element(&ml->ml_rangehigh, rangehigh);
+ if (error)
+ return (error);
+ ml->ml_flags |= MAC_LOMAC_FLAG_RANGE;
+ }
+
+ error = lomac_valid(ml);
+ if (error)
+ return (error);
+
+ return (0);
+}
+
+static int
+lomac_internalize_label(struct label *label, char *element_name,
+ char *element_data, int *claimed)
+{
+ struct mac_lomac *ml, ml_temp;
+ int error;
+
+ if (strcmp(MAC_LOMAC_LABEL_NAME, element_name) != 0)
+ return (0);
+
+ (*claimed)++;
+
+ error = lomac_parse(&ml_temp, element_data);
+ if (error)
+ return (error);
+
+ ml = SLOT(label);
+ *ml = ml_temp;
+
+ return (0);
+}
+
+static void
+lomac_copy_label(struct label *src, struct label *dest)
+{
+
+ *SLOT(dest) = *SLOT(src);
+}
+
+/*
+ * Object-specific entry point implementations are sorted alphabetically by
+ * object type name and then by operation.
+ */
+static int
+lomac_bpfdesc_check_receive(struct bpf_d *d, struct label *dlabel,
+ struct ifnet *ifp, struct label *ifplabel)
+{
+ struct mac_lomac *a, *b;
+
+ if (!lomac_enabled)
+ return (0);
+
+ a = SLOT(dlabel);
+ b = SLOT(ifplabel);
+
+ if (lomac_equal_single(a, b))
+ return (0);
+ return (EACCES);
+}
+
+static void
+lomac_bpfdesc_create(struct ucred *cred, struct bpf_d *d,
+ struct label *dlabel)
+{
+ struct mac_lomac *source, *dest;
+
+ source = SLOT(cred->cr_label);
+ dest = SLOT(dlabel);
+
+ lomac_copy_single(source, dest);
+}
+
+static void
+lomac_bpfdesc_create_mbuf(struct bpf_d *d, struct label *dlabel,
+ struct mbuf *m, struct label *mlabel)
+{
+ struct mac_lomac *source, *dest;
+
+ source = SLOT(dlabel);
+ dest = SLOT(mlabel);
+
+ lomac_copy_single(source, dest);
+}
+
+static int
+lomac_cred_check_relabel(struct ucred *cred, struct label *newlabel)
+{
+ struct mac_lomac *subj, *new;
+ int error;
+
+ subj = SLOT(cred->cr_label);
+ new = SLOT(newlabel);
+
+ /*
+ * If there is a LOMAC label update for the credential, it may be an
+ * update of the single, range, or both.
+ */
+ error = lomac_atmostflags(new, MAC_LOMAC_FLAGS_BOTH);
+ if (error)
+ return (error);
+
+ /*
+ * If the LOMAC label is to be changed, authorize as appropriate.
+ */
+ if (new->ml_flags & MAC_LOMAC_FLAGS_BOTH) {
+ /*
+ * Fill in the missing parts from the previous label.
+ */
+ if ((new->ml_flags & MAC_LOMAC_FLAG_SINGLE) == 0)
+ lomac_copy_single(subj, new);
+ if ((new->ml_flags & MAC_LOMAC_FLAG_RANGE) == 0)
+ lomac_copy_range(subj, new);
+
+ /*
+ * To change the LOMAC range on a credential, the new range
+ * label must be in the current range.
+ */
+ if (!lomac_range_in_range(new, subj))
+ return (EPERM);
+
+ /*
+ * To change the LOMAC single label on a credential, the new
+ * single label must be in the new range. Implicitly from
+ * the previous check, the new single is in the old range.
+ */
+ if (!lomac_single_in_range(new, new))
+ return (EPERM);
+
+ /*
+ * To have EQUAL in any component of the new credential LOMAC
+ * label, the subject must already have EQUAL in their label.
+ */
+ if (lomac_contains_equal(new)) {
+ error = lomac_subject_privileged(subj);
+ if (error)
+ return (error);
+ }
+
+ /*
+ * XXXMAC: Additional consistency tests regarding the single
+ * and range of the new label might be performed here.
+ */
+ }
+
+ return (0);
+}
+
+static int
+lomac_cred_check_visible(struct ucred *cr1, struct ucred *cr2)
+{
+ struct mac_lomac *subj, *obj;
+
+ if (!lomac_enabled)
+ return (0);
+
+ subj = SLOT(cr1->cr_label);
+ obj = SLOT(cr2->cr_label);
+
+ /* XXX: range */
+ if (!lomac_dominate_single(obj, subj))
+ return (ESRCH);
+
+ return (0);
+}
+
+static void
+lomac_cred_create_init(struct ucred *cred)
+{
+ struct mac_lomac *dest;
+
+ dest = SLOT(cred->cr_label);
+
+ lomac_set_single(dest, MAC_LOMAC_TYPE_HIGH, 0);
+ lomac_set_range(dest, MAC_LOMAC_TYPE_LOW, 0, MAC_LOMAC_TYPE_HIGH, 0);
+}
+
+static void
+lomac_cred_create_swapper(struct ucred *cred)
+{
+ struct mac_lomac *dest;
+
+ dest = SLOT(cred->cr_label);
+
+ lomac_set_single(dest, MAC_LOMAC_TYPE_EQUAL, 0);
+ lomac_set_range(dest, MAC_LOMAC_TYPE_LOW, 0, MAC_LOMAC_TYPE_HIGH, 0);
+}
+
+static void
+lomac_cred_relabel(struct ucred *cred, struct label *newlabel)
+{
+ struct mac_lomac *source, *dest;
+
+ source = SLOT(newlabel);
+ dest = SLOT(cred->cr_label);
+
+ try_relabel(source, dest);
+}
+
+static void
+lomac_devfs_create_device(struct ucred *cred, struct mount *mp,
+ struct cdev *dev, struct devfs_dirent *de, struct label *delabel)
+{
+ struct mac_lomac *ml;
+ int lomac_type;
+
+ ml = SLOT(delabel);
+ if (strcmp(dev->si_name, "null") == 0 ||
+ strcmp(dev->si_name, "zero") == 0 ||
+ strcmp(dev->si_name, "random") == 0 ||
+ strncmp(dev->si_name, "fd/", strlen("fd/")) == 0 ||
+ strncmp(dev->si_name, "ttyv", strlen("ttyv")) == 0)
+ lomac_type = MAC_LOMAC_TYPE_EQUAL;
+ else if (ptys_equal &&
+ (strncmp(dev->si_name, "ttyp", strlen("ttyp")) == 0 ||
+ strncmp(dev->si_name, "ptyp", strlen("ptyp")) == 0))
+ lomac_type = MAC_LOMAC_TYPE_EQUAL;
+ else
+ lomac_type = MAC_LOMAC_TYPE_HIGH;
+ lomac_set_single(ml, lomac_type, 0);
+}
+
+static void
+lomac_devfs_create_directory(struct mount *mp, char *dirname, int dirnamelen,
+ struct devfs_dirent *de, struct label *delabel)
+{
+ struct mac_lomac *ml;
+
+ ml = SLOT(delabel);
+ lomac_set_single(ml, MAC_LOMAC_TYPE_HIGH, 0);
+}
+
+static void
+lomac_devfs_create_symlink(struct ucred *cred, struct mount *mp,
+ struct devfs_dirent *dd, struct label *ddlabel, struct devfs_dirent *de,
+ struct label *delabel)
+{
+ struct mac_lomac *source, *dest;
+
+ source = SLOT(cred->cr_label);
+ dest = SLOT(delabel);
+
+ lomac_copy_single(source, dest);
+}
+
+static void
+lomac_devfs_update(struct mount *mp, struct devfs_dirent *de,
+ struct label *delabel, struct vnode *vp, struct label *vplabel)
+{
+ struct mac_lomac *source, *dest;
+
+ source = SLOT(vplabel);
+ dest = SLOT(delabel);
+
+ lomac_copy(source, dest);
+}
+
+static void
+lomac_devfs_vnode_associate(struct mount *mp, struct label *mplabel,
+ struct devfs_dirent *de, struct label *delabel, struct vnode *vp,
+ struct label *vplabel)
+{
+ struct mac_lomac *source, *dest;
+
+ source = SLOT(delabel);
+ dest = SLOT(vplabel);
+
+ lomac_copy_single(source, dest);
+}
+
+static int
+lomac_ifnet_check_relabel(struct ucred *cred, struct ifnet *ifp,
+ struct label *ifplabel, struct label *newlabel)
+{
+ struct mac_lomac *subj, *new;
+ int error;
+
+ subj = SLOT(cred->cr_label);
+ new = SLOT(newlabel);
+
+ /*
+ * If there is a LOMAC label update for the interface, it may be an
+ * update of the single, range, or both.
+ */
+ error = lomac_atmostflags(new, MAC_LOMAC_FLAGS_BOTH);
+ if (error)
+ return (error);
+
+ /*
+ * Relabling network interfaces requires LOMAC privilege.
+ */
+ error = lomac_subject_privileged(subj);
+ if (error)
+ return (error);
+
+ /*
+ * If the LOMAC label is to be changed, authorize as appropriate.
+ */
+ if (new->ml_flags & MAC_LOMAC_FLAGS_BOTH) {
+ /*
+ * Fill in the missing parts from the previous label.
+ */
+ if ((new->ml_flags & MAC_LOMAC_FLAG_SINGLE) == 0)
+ lomac_copy_single(subj, new);
+ if ((new->ml_flags & MAC_LOMAC_FLAG_RANGE) == 0)
+ lomac_copy_range(subj, new);
+
+ /*
+ * Rely on the traditional superuser status for the LOMAC
+ * interface relabel requirements. XXXMAC: This will go
+ * away.
+ *
+ * XXXRW: This is also redundant to a higher layer check.
+ */
+ error = priv_check_cred(cred, PRIV_NET_SETIFMAC, 0);
+ if (error)
+ return (EPERM);
+
+ /*
+ * XXXMAC: Additional consistency tests regarding the single
+ * and the range of the new label might be performed here.
+ */
+ }
+
+ return (0);
+}
+
+static int
+lomac_ifnet_check_transmit(struct ifnet *ifp, struct label *ifplabel,
+ struct mbuf *m, struct label *mlabel)
+{
+ struct mac_lomac *p, *i;
+
+ if (!lomac_enabled)
+ return (0);
+
+ p = SLOT(mlabel);
+ i = SLOT(ifplabel);
+
+ return (lomac_single_in_range(p, i) ? 0 : EACCES);
+}
+
+static void
+lomac_ifnet_create(struct ifnet *ifp, struct label *ifplabel)
+{
+ char tifname[IFNAMSIZ], *p, *q;
+ char tiflist[sizeof(trusted_interfaces)];
+ struct mac_lomac *dest;
+ int len, grade;
+
+ dest = SLOT(ifplabel);
+
+ if (ifp->if_type == IFT_LOOP) {
+ grade = MAC_LOMAC_TYPE_EQUAL;
+ goto set;
+ }
+
+ if (trust_all_interfaces) {
+ grade = MAC_LOMAC_TYPE_HIGH;
+ goto set;
+ }
+
+ grade = MAC_LOMAC_TYPE_LOW;
+
+ if (trusted_interfaces[0] == '\0' ||
+ !strvalid(trusted_interfaces, sizeof(trusted_interfaces)))
+ goto set;
+
+ bzero(tiflist, sizeof(tiflist));
+ for (p = trusted_interfaces, q = tiflist; *p != '\0'; p++, q++)
+ if(*p != ' ' && *p != '\t')
+ *q = *p;
+
+ for (p = q = tiflist;; p++) {
+ if (*p == ',' || *p == '\0') {
+ len = p - q;
+ if (len < IFNAMSIZ) {
+ bzero(tifname, sizeof(tifname));
+ bcopy(q, tifname, len);
+ if (strcmp(tifname, ifp->if_xname) == 0) {
+ grade = MAC_LOMAC_TYPE_HIGH;
+ break;
+ }
+ }
+ else {
+ *p = '\0';
+ printf("MAC/LOMAC warning: interface name "
+ "\"%s\" is too long (must be < %d)\n",
+ q, IFNAMSIZ);
+ }
+ if (*p == '\0')
+ break;
+ q = p + 1;
+ }
+ }
+set:
+ lomac_set_single(dest, grade, 0);
+ lomac_set_range(dest, grade, 0, grade, 0);
+}
+
+static void
+lomac_ifnet_create_mbuf(struct ifnet *ifp, struct label *ifplabel,
+ struct mbuf *m, struct label *mlabel)
+{
+ struct mac_lomac *source, *dest;
+
+ source = SLOT(ifplabel);
+ dest = SLOT(mlabel);
+
+ lomac_copy_single(source, dest);
+}
+
+static void
+lomac_ifnet_relabel(struct ucred *cred, struct ifnet *ifp,
+ struct label *ifplabel, struct label *newlabel)
+{
+ struct mac_lomac *source, *dest;
+
+ source = SLOT(newlabel);
+ dest = SLOT(ifplabel);
+
+ try_relabel(source, dest);
+}
+
+static int
+lomac_inpcb_check_deliver(struct inpcb *inp, struct label *inplabel,
+ struct mbuf *m, struct label *mlabel)
+{
+ struct mac_lomac *p, *i;
+
+ if (!lomac_enabled)
+ return (0);
+
+ p = SLOT(mlabel);
+ i = SLOT(inplabel);
+
+ return (lomac_equal_single(p, i) ? 0 : EACCES);
+}
+
+static int
+lomac_inpcb_check_visible(struct ucred *cred, struct inpcb *inp,
+ struct label *inplabel)
+{
+ struct mac_lomac *subj, *obj;
+
+ if (!lomac_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(inplabel);
+
+ if (!lomac_dominate_single(obj, subj))
+ return (ENOENT);
+
+ return (0);
+}
+
+static void
+lomac_inpcb_create(struct socket *so, struct label *solabel,
+ struct inpcb *inp, struct label *inplabel)
+{
+ struct mac_lomac *source, *dest;
+
+ source = SLOT(solabel);
+ dest = SLOT(inplabel);
+
+ lomac_copy_single(source, dest);
+}
+
+static void
+lomac_inpcb_create_mbuf(struct inpcb *inp, struct label *inplabel,
+ struct mbuf *m, struct label *mlabel)
+{
+ struct mac_lomac *source, *dest;
+
+ source = SLOT(inplabel);
+ dest = SLOT(mlabel);
+
+ lomac_copy_single(source, dest);
+}
+
+static void
+lomac_inpcb_sosetlabel(struct socket *so, struct label *solabel,
+ struct inpcb *inp, struct label *inplabel)
+{
+ struct mac_lomac *source, *dest;
+
+ source = SLOT(solabel);
+ dest = SLOT(inplabel);
+
+ lomac_copy_single(source, dest);
+}
+
+static void
+lomac_ip6q_create(struct mbuf *m, struct label *mlabel, struct ip6q *q6,
+ struct label *q6label)
+{
+ struct mac_lomac *source, *dest;
+
+ source = SLOT(mlabel);
+ dest = SLOT(q6label);
+
+ lomac_copy_single(source, dest);
+}
+
+static int
+lomac_ip6q_match(struct mbuf *m, struct label *mlabel, struct ip6q *q6,
+ struct label *q6label)
+{
+ struct mac_lomac *a, *b;
+
+ a = SLOT(q6label);
+ b = SLOT(mlabel);
+
+ return (lomac_equal_single(a, b));
+}
+
+static void
+lomac_ip6q_reassemble(struct ip6q *q6, struct label *q6label, struct mbuf *m,
+ struct label *mlabel)
+{
+ struct mac_lomac *source, *dest;
+
+ source = SLOT(q6label);
+ dest = SLOT(mlabel);
+
+ /* Just use the head, since we require them all to match. */
+ lomac_copy_single(source, dest);
+}
+
+static void
+lomac_ip6q_update(struct mbuf *m, struct label *mlabel, struct ip6q *q6,
+ struct label *q6label)
+{
+
+ /* NOOP: we only accept matching labels, so no need to update */
+}
+
+static void
+lomac_ipq_create(struct mbuf *m, struct label *mlabel, struct ipq *q,
+ struct label *qlabel)
+{
+ struct mac_lomac *source, *dest;
+
+ source = SLOT(mlabel);
+ dest = SLOT(qlabel);
+
+ lomac_copy_single(source, dest);
+}
+
+static int
+lomac_ipq_match(struct mbuf *m, struct label *mlabel, struct ipq *q,
+ struct label *qlabel)
+{
+ struct mac_lomac *a, *b;
+
+ a = SLOT(qlabel);
+ b = SLOT(mlabel);
+
+ return (lomac_equal_single(a, b));
+}
+
+static void
+lomac_ipq_reassemble(struct ipq *q, struct label *qlabel, struct mbuf *m,
+ struct label *mlabel)
+{
+ struct mac_lomac *source, *dest;
+
+ source = SLOT(qlabel);
+ dest = SLOT(mlabel);
+
+ /* Just use the head, since we require them all to match. */
+ lomac_copy_single(source, dest);
+}
+
+static void
+lomac_ipq_update(struct mbuf *m, struct label *mlabel, struct ipq *q,
+ struct label *qlabel)
+{
+
+ /* NOOP: we only accept matching labels, so no need to update */
+}
+
+static int
+lomac_kld_check_load(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel)
+{
+ struct mac_lomac *subj, *obj;
+
+ if (!lomac_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(vplabel);
+
+ if (lomac_subject_privileged(subj))
+ return (EPERM);
+
+ if (!lomac_high_single(obj))
+ return (EACCES);
+
+ return (0);
+}
+
+static void
+lomac_mount_create(struct ucred *cred, struct mount *mp,
+ struct label *mplabel)
+{
+ struct mac_lomac *source, *dest;
+
+ source = SLOT(cred->cr_label);
+ dest = SLOT(mplabel);
+ lomac_copy_single(source, dest);
+}
+
+static void
+lomac_netatalk_aarp_send(struct ifnet *ifp, struct label *ifplabel,
+ struct mbuf *m, struct label *mlabel)
+{
+ struct mac_lomac *dest;
+
+ dest = SLOT(mlabel);
+
+ lomac_set_single(dest, MAC_LOMAC_TYPE_EQUAL, 0);
+}
+
+static void
+lomac_netinet_arp_send(struct ifnet *ifp, struct label *ifplabel,
+ struct mbuf *m, struct label *mlabel)
+{
+ struct mac_lomac *dest;
+
+ dest = SLOT(mlabel);
+
+ lomac_set_single(dest, MAC_LOMAC_TYPE_EQUAL, 0);
+}
+
+static void
+lomac_netinet_firewall_reply(struct mbuf *mrecv, struct label *mrecvlabel,
+ struct mbuf *msend, struct label *msendlabel)
+{
+ struct mac_lomac *source, *dest;
+
+ source = SLOT(mrecvlabel);
+ dest = SLOT(msendlabel);
+
+ lomac_copy_single(source, dest);
+}
+
+static void
+lomac_netinet_firewall_send(struct mbuf *m, struct label *mlabel)
+{
+ struct mac_lomac *dest;
+
+ dest = SLOT(mlabel);
+
+ /* XXX: where is the label for the firewall really comming from? */
+ lomac_set_single(dest, MAC_LOMAC_TYPE_EQUAL, 0);
+}
+
+static void
+lomac_netinet_fragment(struct mbuf *m, struct label *mlabel,
+ struct mbuf *frag, struct label *fraglabel)
+{
+ struct mac_lomac *source, *dest;
+
+ source = SLOT(mlabel);
+ dest = SLOT(fraglabel);
+
+ lomac_copy_single(source, dest);
+}
+
+static void
+lomac_netinet_icmp_reply(struct mbuf *mrecv, struct label *mrecvlabel,
+ struct mbuf *msend, struct label *msendlabel)
+{
+ struct mac_lomac *source, *dest;
+
+ source = SLOT(mrecvlabel);
+ dest = SLOT(msendlabel);
+
+ lomac_copy_single(source, dest);
+}
+
+static void
+lomac_netinet_igmp_send(struct ifnet *ifp, struct label *ifplabel,
+ struct mbuf *m, struct label *mlabel)
+{
+ struct mac_lomac *dest;
+
+ dest = SLOT(mlabel);
+
+ lomac_set_single(dest, MAC_LOMAC_TYPE_EQUAL, 0);
+}
+
+static void
+lomac_netinet6_nd6_send(struct ifnet *ifp, struct label *ifplabel,
+ struct mbuf *m, struct label *mlabel)
+{
+ struct mac_lomac *dest;
+
+ dest = SLOT(mlabel);
+
+ lomac_set_single(dest, MAC_LOMAC_TYPE_EQUAL, 0);
+}
+
+static int
+lomac_pipe_check_ioctl(struct ucred *cred, struct pipepair *pp,
+ struct label *pplabel, unsigned long cmd, void /* caddr_t */ *data)
+{
+
+ if (!lomac_enabled)
+ return (0);
+
+ /* XXX: This will be implemented soon... */
+
+ return (0);
+}
+
+static int
+lomac_pipe_check_read(struct ucred *cred, struct pipepair *pp,
+ struct label *pplabel)
+{
+ struct mac_lomac *subj, *obj;
+
+ if (!lomac_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(pplabel);
+
+ if (!lomac_dominate_single(obj, subj))
+ return (maybe_demote(subj, obj, "reading", "pipe", NULL));
+
+ return (0);
+}
+
+static int
+lomac_pipe_check_relabel(struct ucred *cred, struct pipepair *pp,
+ struct label *pplabel, struct label *newlabel)
+{
+ struct mac_lomac *subj, *obj, *new;
+ int error;
+
+ new = SLOT(newlabel);
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(pplabel);
+
+ /*
+ * If there is a LOMAC label update for a pipe, it must be a single
+ * update.
+ */
+ error = lomac_atmostflags(new, MAC_LOMAC_FLAG_SINGLE);
+ if (error)
+ return (error);
+
+ /*
+ * To perform a relabel of a pipe (LOMAC label or not), LOMAC must
+ * authorize the relabel.
+ */
+ if (!lomac_single_in_range(obj, subj))
+ return (EPERM);
+
+ /*
+ * If the LOMAC label is to be changed, authorize as appropriate.
+ */
+ if (new->ml_flags & MAC_LOMAC_FLAG_SINGLE) {
+ /*
+ * To change the LOMAC label on a pipe, the new pipe label
+ * must be in the subject range.
+ */
+ if (!lomac_single_in_range(new, subj))
+ return (EPERM);
+
+ /*
+ * To change the LOMAC label on a pipe to be EQUAL, the
+ * subject must have appropriate privilege.
+ */
+ if (lomac_contains_equal(new)) {
+ error = lomac_subject_privileged(subj);
+ if (error)
+ return (error);
+ }
+ }
+
+ return (0);
+}
+
+static int
+lomac_pipe_check_write(struct ucred *cred, struct pipepair *pp,
+ struct label *pplabel)
+{
+ struct mac_lomac *subj, *obj;
+
+ if (!lomac_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(pplabel);
+
+ if (!lomac_subject_dominate(subj, obj))
+ return (EACCES);
+
+ return (0);
+}
+
+static void
+lomac_pipe_create(struct ucred *cred, struct pipepair *pp,
+ struct label *pplabel)
+{
+ struct mac_lomac *source, *dest;
+
+ source = SLOT(cred->cr_label);
+ dest = SLOT(pplabel);
+
+ lomac_copy_single(source, dest);
+}
+
+static void
+lomac_pipe_relabel(struct ucred *cred, struct pipepair *pp,
+ struct label *pplabel, struct label *newlabel)
+{
+ struct mac_lomac *source, *dest;
+
+ source = SLOT(newlabel);
+ dest = SLOT(pplabel);
+
+ try_relabel(source, dest);
+}
+
+/*
+ * Some system privileges are allowed regardless of integrity grade; others
+ * are allowed only when running with privilege with respect to the LOMAC
+ * policy as they might otherwise allow bypassing of the integrity policy.
+ */
+static int
+lomac_priv_check(struct ucred *cred, int priv)
+{
+ struct mac_lomac *subj;
+ int error;
+
+ if (!lomac_enabled)
+ return (0);
+
+ /*
+ * Exempt only specific privileges from the LOMAC integrity policy.
+ */
+ switch (priv) {
+ case PRIV_KTRACE:
+ case PRIV_MSGBUF:
+
+ /*
+ * Allow processes to manipulate basic process audit properties, and
+ * to submit audit records.
+ */
+ case PRIV_AUDIT_GETAUDIT:
+ case PRIV_AUDIT_SETAUDIT:
+ case PRIV_AUDIT_SUBMIT:
+
+ /*
+ * Allow processes to manipulate their regular UNIX credentials.
+ */
+ case PRIV_CRED_SETUID:
+ case PRIV_CRED_SETEUID:
+ case PRIV_CRED_SETGID:
+ case PRIV_CRED_SETEGID:
+ case PRIV_CRED_SETGROUPS:
+ case PRIV_CRED_SETREUID:
+ case PRIV_CRED_SETREGID:
+ case PRIV_CRED_SETRESUID:
+ case PRIV_CRED_SETRESGID:
+
+ /*
+ * Allow processes to perform system monitoring.
+ */
+ case PRIV_SEEOTHERGIDS:
+ case PRIV_SEEOTHERUIDS:
+ break;
+
+ /*
+ * Allow access to general process debugging facilities. We
+ * separately control debugging based on MAC label.
+ */
+ case PRIV_DEBUG_DIFFCRED:
+ case PRIV_DEBUG_SUGID:
+ case PRIV_DEBUG_UNPRIV:
+
+ /*
+ * Allow manipulating jails.
+ */
+ case PRIV_JAIL_ATTACH:
+
+ /*
+ * Allow privilege with respect to the Partition policy, but not the
+ * Privs policy.
+ */
+ case PRIV_MAC_PARTITION:
+
+ /*
+ * Allow privilege with respect to process resource limits and login
+ * context.
+ */
+ case PRIV_PROC_LIMIT:
+ case PRIV_PROC_SETLOGIN:
+ case PRIV_PROC_SETRLIMIT:
+
+ /*
+ * Allow System V and POSIX IPC privileges.
+ */
+ case PRIV_IPC_READ:
+ case PRIV_IPC_WRITE:
+ case PRIV_IPC_ADMIN:
+ case PRIV_IPC_MSGSIZE:
+ case PRIV_MQ_ADMIN:
+
+ /*
+ * Allow certain scheduler manipulations -- possibly this should be
+ * controlled by more fine-grained policy, as potentially low
+ * integrity processes can deny CPU to higher integrity ones.
+ */
+ case PRIV_SCHED_DIFFCRED:
+ case PRIV_SCHED_SETPRIORITY:
+ case PRIV_SCHED_RTPRIO:
+ case PRIV_SCHED_SETPOLICY:
+ case PRIV_SCHED_SET:
+ case PRIV_SCHED_SETPARAM:
+
+ /*
+ * More IPC privileges.
+ */
+ case PRIV_SEM_WRITE:
+
+ /*
+ * Allow signaling privileges subject to integrity policy.
+ */
+ case PRIV_SIGNAL_DIFFCRED:
+ case PRIV_SIGNAL_SUGID:
+
+ /*
+ * Allow access to only limited sysctls from lower integrity levels;
+ * piggy-back on the Jail definition.
+ */
+ case PRIV_SYSCTL_WRITEJAIL:
+
+ /*
+ * Allow TTY-based privileges, subject to general device access using
+ * labels on TTY device nodes, but not console privilege.
+ */
+ case PRIV_TTY_DRAINWAIT:
+ case PRIV_TTY_DTRWAIT:
+ case PRIV_TTY_EXCLUSIVE:
+ case PRIV_TTY_PRISON:
+ case PRIV_TTY_STI:
+ case PRIV_TTY_SETA:
+
+ /*
+ * Grant most VFS privileges, as almost all are in practice bounded
+ * by more specific checks using labels.
+ */
+ case PRIV_VFS_READ:
+ case PRIV_VFS_WRITE:
+ case PRIV_VFS_ADMIN:
+ case PRIV_VFS_EXEC:
+ case PRIV_VFS_LOOKUP:
+ case PRIV_VFS_CHFLAGS_DEV:
+ case PRIV_VFS_CHOWN:
+ case PRIV_VFS_CHROOT:
+ case PRIV_VFS_RETAINSUGID:
+ case PRIV_VFS_EXCEEDQUOTA:
+ case PRIV_VFS_FCHROOT:
+ case PRIV_VFS_FHOPEN:
+ case PRIV_VFS_FHSTATFS:
+ case PRIV_VFS_GENERATION:
+ case PRIV_VFS_GETFH:
+ case PRIV_VFS_GETQUOTA:
+ case PRIV_VFS_LINK:
+ case PRIV_VFS_MOUNT:
+ case PRIV_VFS_MOUNT_OWNER:
+ case PRIV_VFS_MOUNT_PERM:
+ case PRIV_VFS_MOUNT_SUIDDIR:
+ case PRIV_VFS_MOUNT_NONUSER:
+ case PRIV_VFS_SETGID:
+ case PRIV_VFS_STICKYFILE:
+ case PRIV_VFS_SYSFLAGS:
+ case PRIV_VFS_UNMOUNT:
+
+ /*
+ * Allow VM privileges; it would be nice if these were subject to
+ * resource limits.
+ */
+ case PRIV_VM_MADV_PROTECT:
+ case PRIV_VM_MLOCK:
+ case PRIV_VM_MUNLOCK:
+
+ /*
+ * Allow some but not all network privileges. In general, dont allow
+ * reconfiguring the network stack, just normal use.
+ */
+ case PRIV_NETATALK_RESERVEDPORT:
+ case PRIV_NETINET_RESERVEDPORT:
+ case PRIV_NETINET_RAW:
+ case PRIV_NETINET_REUSEPORT:
+ case PRIV_NETIPX_RESERVEDPORT:
+ case PRIV_NETIPX_RAW:
+ break;
+
+ /*
+ * All remaining system privileges are allow only if the process
+ * holds privilege with respect to the LOMAC policy.
+ */
+ default:
+ subj = SLOT(cred->cr_label);
+ error = lomac_subject_privileged(subj);
+ if (error)
+ return (error);
+ }
+ return (0);
+}
+
+static int
+lomac_proc_check_debug(struct ucred *cred, struct proc *p)
+{
+ struct mac_lomac *subj, *obj;
+
+ if (!lomac_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(p->p_ucred->cr_label);
+
+ /* XXX: range checks */
+ if (!lomac_dominate_single(obj, subj))
+ return (ESRCH);
+ if (!lomac_subject_dominate(subj, obj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+lomac_proc_check_sched(struct ucred *cred, struct proc *p)
+{
+ struct mac_lomac *subj, *obj;
+
+ if (!lomac_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(p->p_ucred->cr_label);
+
+ /* XXX: range checks */
+ if (!lomac_dominate_single(obj, subj))
+ return (ESRCH);
+ if (!lomac_subject_dominate(subj, obj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+lomac_proc_check_signal(struct ucred *cred, struct proc *p, int signum)
+{
+ struct mac_lomac *subj, *obj;
+
+ if (!lomac_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(p->p_ucred->cr_label);
+
+ /* XXX: range checks */
+ if (!lomac_dominate_single(obj, subj))
+ return (ESRCH);
+ if (!lomac_subject_dominate(subj, obj))
+ return (EACCES);
+
+ return (0);
+}
+
+static void
+lomac_proc_destroy_label(struct label *label)
+{
+
+ mtx_destroy(&PSLOT(label)->mtx);
+ free(PSLOT(label), M_LOMAC);
+ PSLOT_SET(label, NULL);
+}
+
+static void
+lomac_proc_init_label(struct label *label)
+{
+
+ PSLOT_SET(label, malloc(sizeof(struct mac_lomac_proc), M_LOMAC,
+ M_ZERO | M_WAITOK));
+ mtx_init(&PSLOT(label)->mtx, "MAC/Lomac proc lock", NULL, MTX_DEF);
+}
+
+static int
+lomac_socket_check_deliver(struct socket *so, struct label *solabel,
+ struct mbuf *m, struct label *mlabel)
+{
+ struct mac_lomac *p, *s;
+
+ if (!lomac_enabled)
+ return (0);
+
+ p = SLOT(mlabel);
+ s = SLOT(solabel);
+
+ return (lomac_equal_single(p, s) ? 0 : EACCES);
+}
+
+static int
+lomac_socket_check_relabel(struct ucred *cred, struct socket *so,
+ struct label *solabel, struct label *newlabel)
+{
+ struct mac_lomac *subj, *obj, *new;
+ int error;
+
+ new = SLOT(newlabel);
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(solabel);
+
+ /*
+ * If there is a LOMAC label update for the socket, it may be an
+ * update of single.
+ */
+ error = lomac_atmostflags(new, MAC_LOMAC_FLAG_SINGLE);
+ if (error)
+ return (error);
+
+ /*
+ * To relabel a socket, the old socket single must be in the subject
+ * range.
+ */
+ if (!lomac_single_in_range(obj, subj))
+ return (EPERM);
+
+ /*
+ * If the LOMAC label is to be changed, authorize as appropriate.
+ */
+ if (new->ml_flags & MAC_LOMAC_FLAG_SINGLE) {
+ /*
+ * To relabel a socket, the new socket single must be in the
+ * subject range.
+ */
+ if (!lomac_single_in_range(new, subj))
+ return (EPERM);
+
+ /*
+ * To change the LOMAC label on the socket to contain EQUAL,
+ * the subject must have appropriate privilege.
+ */
+ if (lomac_contains_equal(new)) {
+ error = lomac_subject_privileged(subj);
+ if (error)
+ return (error);
+ }
+ }
+
+ return (0);
+}
+
+static int
+lomac_socket_check_visible(struct ucred *cred, struct socket *so,
+ struct label *solabel)
+{
+ struct mac_lomac *subj, *obj;
+
+ if (!lomac_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(solabel);
+
+ if (!lomac_dominate_single(obj, subj))
+ return (ENOENT);
+
+ return (0);
+}
+
+static void
+lomac_socket_create(struct ucred *cred, struct socket *so,
+ struct label *solabel)
+{
+ struct mac_lomac *source, *dest;
+
+ source = SLOT(cred->cr_label);
+ dest = SLOT(solabel);
+
+ lomac_copy_single(source, dest);
+}
+
+static void
+lomac_socket_create_mbuf(struct socket *so, struct label *solabel,
+ struct mbuf *m, struct label *mlabel)
+{
+ struct mac_lomac *source, *dest;
+
+ source = SLOT(solabel);
+ dest = SLOT(mlabel);
+
+ lomac_copy_single(source, dest);
+}
+
+static void
+lomac_socket_newconn(struct socket *oldso, struct label *oldsolabel,
+ struct socket *newso, struct label *newsolabel)
+{
+ struct mac_lomac *source, *dest;
+
+ source = SLOT(oldsolabel);
+ dest = SLOT(newsolabel);
+
+ lomac_copy_single(source, dest);
+}
+
+static void
+lomac_socket_relabel(struct ucred *cred, struct socket *so,
+ struct label *solabel, struct label *newlabel)
+{
+ struct mac_lomac *source, *dest;
+
+ source = SLOT(newlabel);
+ dest = SLOT(solabel);
+
+ try_relabel(source, dest);
+}
+
+static void
+lomac_socketpeer_set_from_mbuf(struct mbuf *m, struct label *mlabel,
+ struct socket *so, struct label *sopeerlabel)
+{
+ struct mac_lomac *source, *dest;
+
+ source = SLOT(mlabel);
+ dest = SLOT(sopeerlabel);
+
+ lomac_copy_single(source, dest);
+}
+
+static void
+lomac_socketpeer_set_from_socket(struct socket *oldso,
+ struct label *oldsolabel, struct socket *newso,
+ struct label *newsopeerlabel)
+{
+ struct mac_lomac *source, *dest;
+
+ source = SLOT(oldsolabel);
+ dest = SLOT(newsopeerlabel);
+
+ lomac_copy_single(source, dest);
+}
+
+static void
+lomac_syncache_create(struct label *label, struct inpcb *inp)
+{
+ struct mac_lomac *source, *dest;
+
+ source = SLOT(inp->inp_label);
+ dest = SLOT(label);
+ lomac_copy(source, dest);
+}
+
+static void
+lomac_syncache_create_mbuf(struct label *sc_label, struct mbuf *m,
+ struct label *mlabel)
+{
+ struct mac_lomac *source, *dest;
+
+ source = SLOT(sc_label);
+ dest = SLOT(mlabel);
+ lomac_copy(source, dest);
+}
+
+static int
+lomac_system_check_acct(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel)
+{
+ struct mac_lomac *subj, *obj;
+
+ if (!lomac_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(vplabel);
+
+ if (lomac_subject_privileged(subj))
+ return (EPERM);
+
+ if (!lomac_high_single(obj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+lomac_system_check_auditctl(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel)
+{
+ struct mac_lomac *subj, *obj;
+
+ if (!lomac_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(vplabel);
+
+ if (lomac_subject_privileged(subj))
+ return (EPERM);
+
+ if (!lomac_high_single(obj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+lomac_system_check_swapoff(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel)
+{
+ struct mac_lomac *subj;
+
+ if (!lomac_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+
+ if (lomac_subject_privileged(subj))
+ return (EPERM);
+
+ return (0);
+}
+
+static int
+lomac_system_check_swapon(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel)
+{
+ struct mac_lomac *subj, *obj;
+
+ if (!lomac_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(vplabel);
+
+ if (lomac_subject_privileged(subj))
+ return (EPERM);
+
+ if (!lomac_high_single(obj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+lomac_system_check_sysctl(struct ucred *cred, struct sysctl_oid *oidp,
+ void *arg1, int arg2, struct sysctl_req *req)
+{
+ struct mac_lomac *subj;
+
+ if (!lomac_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+
+ /*
+ * Treat sysctl variables without CTLFLAG_ANYBODY flag as lomac/high,
+ * but also require privilege to change them.
+ */
+ if (req->newptr != NULL && (oidp->oid_kind & CTLFLAG_ANYBODY) == 0) {
+#ifdef notdef
+ if (!lomac_subject_dominate_high(subj))
+ return (EACCES);
+#endif
+
+ if (lomac_subject_privileged(subj))
+ return (EPERM);
+ }
+
+ return (0);
+}
+
+static void
+lomac_thread_userret(struct thread *td)
+{
+ struct proc *p = td->td_proc;
+ struct mac_lomac_proc *subj = PSLOT(p->p_label);
+ struct ucred *newcred, *oldcred;
+ int dodrop;
+
+ mtx_lock(&subj->mtx);
+ if (subj->mac_lomac.ml_flags & MAC_LOMAC_FLAG_UPDATE) {
+ dodrop = 0;
+ mtx_unlock(&subj->mtx);
+ newcred = crget();
+ /*
+ * Prevent a lock order reversal in mac_proc_vm_revoke;
+ * ideally, the other user of subj->mtx wouldn't be holding
+ * Giant.
+ */
+ mtx_lock(&Giant);
+ PROC_LOCK(p);
+ mtx_lock(&subj->mtx);
+ /*
+ * Check if we lost the race while allocating the cred.
+ */
+ if ((subj->mac_lomac.ml_flags & MAC_LOMAC_FLAG_UPDATE) == 0) {
+ crfree(newcred);
+ goto out;
+ }
+ oldcred = p->p_ucred;
+ crcopy(newcred, oldcred);
+ crhold(newcred);
+ lomac_copy(&subj->mac_lomac, SLOT(newcred->cr_label));
+ p->p_ucred = newcred;
+ crfree(oldcred);
+ dodrop = 1;
+ out:
+ mtx_unlock(&subj->mtx);
+ PROC_UNLOCK(p);
+ if (dodrop)
+ mac_proc_vm_revoke(curthread);
+ mtx_unlock(&Giant);
+ } else {
+ mtx_unlock(&subj->mtx);
+ }
+}
+
+static int
+lomac_vnode_associate_extattr(struct mount *mp, struct label *mplabel,
+ struct vnode *vp, struct label *vplabel)
+{
+ struct mac_lomac ml_temp, *source, *dest;
+ int buflen, error;
+
+ source = SLOT(mplabel);
+ dest = SLOT(vplabel);
+
+ buflen = sizeof(ml_temp);
+ bzero(&ml_temp, buflen);
+
+ error = vn_extattr_get(vp, IO_NODELOCKED, MAC_LOMAC_EXTATTR_NAMESPACE,
+ MAC_LOMAC_EXTATTR_NAME, &buflen, (char *)&ml_temp, curthread);
+ if (error == ENOATTR || error == EOPNOTSUPP) {
+ /* Fall back to the mntlabel. */
+ lomac_copy_single(source, dest);
+ return (0);
+ } else if (error)
+ return (error);
+
+ if (buflen != sizeof(ml_temp)) {
+ if (buflen != sizeof(ml_temp) - sizeof(ml_temp.ml_auxsingle)) {
+ printf("lomac_vnode_associate_extattr: bad size %d\n",
+ buflen);
+ return (EPERM);
+ }
+ bzero(&ml_temp.ml_auxsingle, sizeof(ml_temp.ml_auxsingle));
+ buflen = sizeof(ml_temp);
+ (void)vn_extattr_set(vp, IO_NODELOCKED,
+ MAC_LOMAC_EXTATTR_NAMESPACE, MAC_LOMAC_EXTATTR_NAME,
+ buflen, (char *)&ml_temp, curthread);
+ }
+ if (lomac_valid(&ml_temp) != 0) {
+ printf("lomac_vnode_associate_extattr: invalid\n");
+ return (EPERM);
+ }
+ if ((ml_temp.ml_flags & MAC_LOMAC_FLAGS_BOTH) !=
+ MAC_LOMAC_FLAG_SINGLE) {
+ printf("lomac_vnode_associate_extattr: not single\n");
+ return (EPERM);
+ }
+
+ lomac_copy_single(&ml_temp, dest);
+ return (0);
+}
+
+static void
+lomac_vnode_associate_singlelabel(struct mount *mp, struct label *mplabel,
+ struct vnode *vp, struct label *vplabel)
+{
+ struct mac_lomac *source, *dest;
+
+ source = SLOT(mplabel);
+ dest = SLOT(vplabel);
+
+ lomac_copy_single(source, dest);
+}
+
+static int
+lomac_vnode_check_create(struct ucred *cred, struct vnode *dvp,
+ struct label *dvplabel, struct componentname *cnp, struct vattr *vap)
+{
+ struct mac_lomac *subj, *obj;
+
+ if (!lomac_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(dvplabel);
+
+ if (!lomac_subject_dominate(subj, obj))
+ return (EACCES);
+ if (obj->ml_flags & MAC_LOMAC_FLAG_AUX &&
+ !lomac_dominate_element(&subj->ml_single, &obj->ml_auxsingle))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+lomac_vnode_check_deleteacl(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, acl_type_t type)
+{
+ struct mac_lomac *subj, *obj;
+
+ if (!lomac_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(vplabel);
+
+ if (!lomac_subject_dominate(subj, obj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+lomac_vnode_check_link(struct ucred *cred, struct vnode *dvp,
+ struct label *dvplabel, struct vnode *vp, struct label *vplabel,
+ struct componentname *cnp)
+{
+ struct mac_lomac *subj, *obj;
+
+ if (!lomac_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(dvplabel);
+
+ if (!lomac_subject_dominate(subj, obj))
+ return (EACCES);
+
+ obj = SLOT(vplabel);
+
+ if (!lomac_subject_dominate(subj, obj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+lomac_vnode_check_mmap(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, int prot, int flags)
+{
+ struct mac_lomac *subj, *obj;
+
+ /*
+ * Rely on the use of open()-time protections to handle
+ * non-revocation cases.
+ */
+ if (!lomac_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(vplabel);
+
+ if (((prot & VM_PROT_WRITE) != 0) && ((flags & MAP_SHARED) != 0)) {
+ if (!lomac_subject_dominate(subj, obj))
+ return (EACCES);
+ }
+ if (prot & (VM_PROT_READ | VM_PROT_EXECUTE)) {
+ if (!lomac_dominate_single(obj, subj))
+ return (maybe_demote(subj, obj, "mapping", "file", vp));
+ }
+
+ return (0);
+}
+
+static void
+lomac_vnode_check_mmap_downgrade(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, /* XXX vm_prot_t */ int *prot)
+{
+ struct mac_lomac *subj, *obj;
+
+ /*
+ * Rely on the use of open()-time protections to handle
+ * non-revocation cases.
+ */
+ if (!lomac_enabled || !revocation_enabled)
+ return;
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(vplabel);
+
+ if (!lomac_subject_dominate(subj, obj))
+ *prot &= ~VM_PROT_WRITE;
+}
+
+static int
+lomac_vnode_check_open(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, accmode_t accmode)
+{
+ struct mac_lomac *subj, *obj;
+
+ if (!lomac_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(vplabel);
+
+ /* XXX privilege override for admin? */
+ if (accmode & (VWRITE | VAPPEND | VADMIN)) {
+ if (!lomac_subject_dominate(subj, obj))
+ return (EACCES);
+ }
+
+ return (0);
+}
+
+static int
+lomac_vnode_check_read(struct ucred *active_cred, struct ucred *file_cred,
+ struct vnode *vp, struct label *vplabel)
+{
+ struct mac_lomac *subj, *obj;
+
+ if (!lomac_enabled || !revocation_enabled)
+ return (0);
+
+ subj = SLOT(active_cred->cr_label);
+ obj = SLOT(vplabel);
+
+ if (!lomac_dominate_single(obj, subj))
+ return (maybe_demote(subj, obj, "reading", "file", vp));
+
+ return (0);
+}
+
+static int
+lomac_vnode_check_relabel(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, struct label *newlabel)
+{
+ struct mac_lomac *old, *new, *subj;
+ int error;
+
+ old = SLOT(vplabel);
+ new = SLOT(newlabel);
+ subj = SLOT(cred->cr_label);
+
+ /*
+ * If there is a LOMAC label update for the vnode, it must be a
+ * single label, with an optional explicit auxiliary single.
+ */
+ error = lomac_atmostflags(new,
+ MAC_LOMAC_FLAG_SINGLE | MAC_LOMAC_FLAG_AUX);
+ if (error)
+ return (error);
+
+ /*
+ * To perform a relabel of the vnode (LOMAC label or not), LOMAC must
+ * authorize the relabel.
+ */
+ if (!lomac_single_in_range(old, subj))
+ return (EPERM);
+
+ /*
+ * If the LOMAC label is to be changed, authorize as appropriate.
+ */
+ if (new->ml_flags & MAC_LOMAC_FLAG_SINGLE) {
+ /*
+ * To change the LOMAC label on a vnode, the new vnode label
+ * must be in the subject range.
+ */
+ if (!lomac_single_in_range(new, subj))
+ return (EPERM);
+
+ /*
+ * To change the LOMAC label on the vnode to be EQUAL, the
+ * subject must have appropriate privilege.
+ */
+ if (lomac_contains_equal(new)) {
+ error = lomac_subject_privileged(subj);
+ if (error)
+ return (error);
+ }
+ }
+ if (new->ml_flags & MAC_LOMAC_FLAG_AUX) {
+ /*
+ * Fill in the missing parts from the previous label.
+ */
+ if ((new->ml_flags & MAC_LOMAC_FLAG_SINGLE) == 0)
+ lomac_copy_single(subj, new);
+
+ /*
+ * To change the auxiliary LOMAC label on a vnode, the new
+ * vnode label must be in the subject range.
+ */
+ if (!lomac_auxsingle_in_range(new, subj))
+ return (EPERM);
+
+ /*
+ * To change the auxiliary LOMAC label on the vnode to be
+ * EQUAL, the subject must have appropriate privilege.
+ */
+ if (lomac_contains_equal(new)) {
+ error = lomac_subject_privileged(subj);
+ if (error)
+ return (error);
+ }
+ }
+
+ return (0);
+}
+
+static int
+lomac_vnode_check_rename_from(struct ucred *cred, struct vnode *dvp,
+ struct label *dvplabel, struct vnode *vp, struct label *vplabel,
+ struct componentname *cnp)
+{
+ struct mac_lomac *subj, *obj;
+
+ if (!lomac_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(dvplabel);
+
+ if (!lomac_subject_dominate(subj, obj))
+ return (EACCES);
+
+ obj = SLOT(vplabel);
+
+ if (!lomac_subject_dominate(subj, obj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+lomac_vnode_check_rename_to(struct ucred *cred, struct vnode *dvp,
+ struct label *dvplabel, struct vnode *vp, struct label *vplabel,
+ int samedir, struct componentname *cnp)
+{
+ struct mac_lomac *subj, *obj;
+
+ if (!lomac_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(dvplabel);
+
+ if (!lomac_subject_dominate(subj, obj))
+ return (EACCES);
+
+ if (vp != NULL) {
+ obj = SLOT(vplabel);
+
+ if (!lomac_subject_dominate(subj, obj))
+ return (EACCES);
+ }
+
+ return (0);
+}
+
+static int
+lomac_vnode_check_revoke(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel)
+{
+ struct mac_lomac *subj, *obj;
+
+ if (!lomac_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(vplabel);
+
+ if (!lomac_subject_dominate(subj, obj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+lomac_vnode_check_setacl(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, acl_type_t type, struct acl *acl)
+{
+ struct mac_lomac *subj, *obj;
+
+ if (!lomac_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(vplabel);
+
+ if (!lomac_subject_dominate(subj, obj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+lomac_vnode_check_setextattr(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, int attrnamespace, const char *name,
+ struct uio *uio)
+{
+ struct mac_lomac *subj, *obj;
+
+ if (!lomac_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(vplabel);
+
+ if (!lomac_subject_dominate(subj, obj))
+ return (EACCES);
+
+ /* XXX: protect the MAC EA in a special way? */
+
+ return (0);
+}
+
+static int
+lomac_vnode_check_setflags(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, u_long flags)
+{
+ struct mac_lomac *subj, *obj;
+
+ if (!lomac_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(vplabel);
+
+ if (!lomac_subject_dominate(subj, obj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+lomac_vnode_check_setmode(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, mode_t mode)
+{
+ struct mac_lomac *subj, *obj;
+
+ if (!lomac_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(vplabel);
+
+ if (!lomac_subject_dominate(subj, obj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+lomac_vnode_check_setowner(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, uid_t uid, gid_t gid)
+{
+ struct mac_lomac *subj, *obj;
+
+ if (!lomac_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(vplabel);
+
+ if (!lomac_subject_dominate(subj, obj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+lomac_vnode_check_setutimes(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, struct timespec atime, struct timespec mtime)
+{
+ struct mac_lomac *subj, *obj;
+
+ if (!lomac_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(vplabel);
+
+ if (!lomac_subject_dominate(subj, obj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+lomac_vnode_check_unlink(struct ucred *cred, struct vnode *dvp,
+ struct label *dvplabel, struct vnode *vp, struct label *vplabel,
+ struct componentname *cnp)
+{
+ struct mac_lomac *subj, *obj;
+
+ if (!lomac_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(dvplabel);
+
+ if (!lomac_subject_dominate(subj, obj))
+ return (EACCES);
+
+ obj = SLOT(vplabel);
+
+ if (!lomac_subject_dominate(subj, obj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+lomac_vnode_check_write(struct ucred *active_cred,
+ struct ucred *file_cred, struct vnode *vp, struct label *vplabel)
+{
+ struct mac_lomac *subj, *obj;
+
+ if (!lomac_enabled || !revocation_enabled)
+ return (0);
+
+ subj = SLOT(active_cred->cr_label);
+ obj = SLOT(vplabel);
+
+ if (!lomac_subject_dominate(subj, obj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+lomac_vnode_create_extattr(struct ucred *cred, struct mount *mp,
+ struct label *mplabel, struct vnode *dvp, struct label *dvplabel,
+ struct vnode *vp, struct label *vplabel, struct componentname *cnp)
+{
+ struct mac_lomac *source, *dest, *dir, temp;
+ size_t buflen;
+ int error;
+
+ buflen = sizeof(temp);
+ bzero(&temp, buflen);
+
+ source = SLOT(cred->cr_label);
+ dest = SLOT(vplabel);
+ dir = SLOT(dvplabel);
+ if (dir->ml_flags & MAC_LOMAC_FLAG_AUX) {
+ lomac_copy_auxsingle(dir, &temp);
+ lomac_set_single(&temp, dir->ml_auxsingle.mle_type,
+ dir->ml_auxsingle.mle_grade);
+ } else {
+ lomac_copy_single(source, &temp);
+ }
+
+ error = vn_extattr_set(vp, IO_NODELOCKED, MAC_LOMAC_EXTATTR_NAMESPACE,
+ MAC_LOMAC_EXTATTR_NAME, buflen, (char *)&temp, curthread);
+ if (error == 0)
+ lomac_copy(&temp, dest);
+ return (error);
+}
+
+static void
+lomac_vnode_execve_transition(struct ucred *old, struct ucred *new,
+ struct vnode *vp, struct label *vplabel, struct label *interpvplabel,
+ struct image_params *imgp, struct label *execlabel)
+{
+ struct mac_lomac *source, *dest, *obj, *robj;
+
+ source = SLOT(old->cr_label);
+ dest = SLOT(new->cr_label);
+ obj = SLOT(vplabel);
+ robj = interpvplabel != NULL ? SLOT(interpvplabel) : obj;
+
+ lomac_copy(source, dest);
+ /*
+ * If there's an auxiliary label on the real object, respect it and
+ * assume that this level should be assumed immediately if a higher
+ * level is currently in place.
+ */
+ if (robj->ml_flags & MAC_LOMAC_FLAG_AUX &&
+ !lomac_dominate_element(&robj->ml_auxsingle, &dest->ml_single)
+ && lomac_auxsingle_in_range(robj, dest))
+ lomac_set_single(dest, robj->ml_auxsingle.mle_type,
+ robj->ml_auxsingle.mle_grade);
+ /*
+ * Restructuring to use the execve transitioning mechanism instead of
+ * the normal demotion mechanism here would be difficult, so just
+ * copy the label over and perform standard demotion. This is also
+ * non-optimal because it will result in the intermediate label "new"
+ * being created and immediately recycled.
+ */
+ if (lomac_enabled && revocation_enabled &&
+ !lomac_dominate_single(obj, source))
+ (void)maybe_demote(source, obj, "executing", "file", vp);
+}
+
+static int
+lomac_vnode_execve_will_transition(struct ucred *old, struct vnode *vp,
+ struct label *vplabel, struct label *interpvplabel,
+ struct image_params *imgp, struct label *execlabel)
+{
+ struct mac_lomac *subj, *obj, *robj;
+
+ if (!lomac_enabled || !revocation_enabled)
+ return (0);
+
+ subj = SLOT(old->cr_label);
+ obj = SLOT(vplabel);
+ robj = interpvplabel != NULL ? SLOT(interpvplabel) : obj;
+
+ return ((robj->ml_flags & MAC_LOMAC_FLAG_AUX &&
+ !lomac_dominate_element(&robj->ml_auxsingle, &subj->ml_single)
+ && lomac_auxsingle_in_range(robj, subj)) ||
+ !lomac_dominate_single(obj, subj));
+}
+
+static void
+lomac_vnode_relabel(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, struct label *newlabel)
+{
+ struct mac_lomac *source, *dest;
+
+ source = SLOT(newlabel);
+ dest = SLOT(vplabel);
+
+ try_relabel(source, dest);
+}
+
+static int
+lomac_vnode_setlabel_extattr(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, struct label *intlabel)
+{
+ struct mac_lomac *source, temp;
+ size_t buflen;
+ int error;
+
+ buflen = sizeof(temp);
+ bzero(&temp, buflen);
+
+ source = SLOT(intlabel);
+ if ((source->ml_flags & MAC_LOMAC_FLAG_SINGLE) == 0)
+ return (0);
+
+ lomac_copy_single(source, &temp);
+ error = vn_extattr_set(vp, IO_NODELOCKED, MAC_LOMAC_EXTATTR_NAMESPACE,
+ MAC_LOMAC_EXTATTR_NAME, buflen, (char *)&temp, curthread);
+ return (error);
+}
+
+static struct mac_policy_ops lomac_ops =
+{
+ .mpo_init = lomac_init,
+
+ .mpo_bpfdesc_check_receive = lomac_bpfdesc_check_receive,
+ .mpo_bpfdesc_create = lomac_bpfdesc_create,
+ .mpo_bpfdesc_create_mbuf = lomac_bpfdesc_create_mbuf,
+ .mpo_bpfdesc_destroy_label = lomac_destroy_label,
+ .mpo_bpfdesc_init_label = lomac_init_label,
+
+ .mpo_cred_check_relabel = lomac_cred_check_relabel,
+ .mpo_cred_check_visible = lomac_cred_check_visible,
+ .mpo_cred_copy_label = lomac_copy_label,
+ .mpo_cred_create_swapper = lomac_cred_create_swapper,
+ .mpo_cred_create_init = lomac_cred_create_init,
+ .mpo_cred_destroy_label = lomac_destroy_label,
+ .mpo_cred_externalize_label = lomac_externalize_label,
+ .mpo_cred_init_label = lomac_init_label,
+ .mpo_cred_internalize_label = lomac_internalize_label,
+ .mpo_cred_relabel = lomac_cred_relabel,
+
+ .mpo_devfs_create_device = lomac_devfs_create_device,
+ .mpo_devfs_create_directory = lomac_devfs_create_directory,
+ .mpo_devfs_create_symlink = lomac_devfs_create_symlink,
+ .mpo_devfs_destroy_label = lomac_destroy_label,
+ .mpo_devfs_init_label = lomac_init_label,
+ .mpo_devfs_update = lomac_devfs_update,
+ .mpo_devfs_vnode_associate = lomac_devfs_vnode_associate,
+
+ .mpo_ifnet_check_relabel = lomac_ifnet_check_relabel,
+ .mpo_ifnet_check_transmit = lomac_ifnet_check_transmit,
+ .mpo_ifnet_copy_label = lomac_copy_label,
+ .mpo_ifnet_create = lomac_ifnet_create,
+ .mpo_ifnet_create_mbuf = lomac_ifnet_create_mbuf,
+ .mpo_ifnet_destroy_label = lomac_destroy_label,
+ .mpo_ifnet_externalize_label = lomac_externalize_label,
+ .mpo_ifnet_init_label = lomac_init_label,
+ .mpo_ifnet_internalize_label = lomac_internalize_label,
+ .mpo_ifnet_relabel = lomac_ifnet_relabel,
+
+ .mpo_syncache_create = lomac_syncache_create,
+ .mpo_syncache_destroy_label = lomac_destroy_label,
+ .mpo_syncache_init_label = lomac_init_label_waitcheck,
+
+ .mpo_inpcb_check_deliver = lomac_inpcb_check_deliver,
+ .mpo_inpcb_check_visible = lomac_inpcb_check_visible,
+ .mpo_inpcb_create = lomac_inpcb_create,
+ .mpo_inpcb_create_mbuf = lomac_inpcb_create_mbuf,
+ .mpo_inpcb_destroy_label = lomac_destroy_label,
+ .mpo_inpcb_init_label = lomac_init_label_waitcheck,
+ .mpo_inpcb_sosetlabel = lomac_inpcb_sosetlabel,
+
+ .mpo_ip6q_create = lomac_ip6q_create,
+ .mpo_ip6q_destroy_label = lomac_destroy_label,
+ .mpo_ip6q_init_label = lomac_init_label_waitcheck,
+ .mpo_ip6q_match = lomac_ip6q_match,
+ .mpo_ip6q_reassemble = lomac_ip6q_reassemble,
+ .mpo_ip6q_update = lomac_ip6q_update,
+
+ .mpo_ipq_create = lomac_ipq_create,
+ .mpo_ipq_destroy_label = lomac_destroy_label,
+ .mpo_ipq_init_label = lomac_init_label_waitcheck,
+ .mpo_ipq_match = lomac_ipq_match,
+ .mpo_ipq_reassemble = lomac_ipq_reassemble,
+ .mpo_ipq_update = lomac_ipq_update,
+
+ .mpo_kld_check_load = lomac_kld_check_load,
+
+ .mpo_mbuf_copy_label = lomac_copy_label,
+ .mpo_mbuf_destroy_label = lomac_destroy_label,
+ .mpo_mbuf_init_label = lomac_init_label_waitcheck,
+
+ .mpo_mount_create = lomac_mount_create,
+ .mpo_mount_destroy_label = lomac_destroy_label,
+ .mpo_mount_init_label = lomac_init_label,
+
+ .mpo_netatalk_aarp_send = lomac_netatalk_aarp_send,
+
+ .mpo_netinet_arp_send = lomac_netinet_arp_send,
+ .mpo_netinet_firewall_reply = lomac_netinet_firewall_reply,
+ .mpo_netinet_firewall_send = lomac_netinet_firewall_send,
+ .mpo_netinet_fragment = lomac_netinet_fragment,
+ .mpo_netinet_icmp_reply = lomac_netinet_icmp_reply,
+ .mpo_netinet_igmp_send = lomac_netinet_igmp_send,
+
+ .mpo_netinet6_nd6_send = lomac_netinet6_nd6_send,
+
+ .mpo_pipe_check_ioctl = lomac_pipe_check_ioctl,
+ .mpo_pipe_check_read = lomac_pipe_check_read,
+ .mpo_pipe_check_relabel = lomac_pipe_check_relabel,
+ .mpo_pipe_check_write = lomac_pipe_check_write,
+ .mpo_pipe_copy_label = lomac_copy_label,
+ .mpo_pipe_create = lomac_pipe_create,
+ .mpo_pipe_destroy_label = lomac_destroy_label,
+ .mpo_pipe_externalize_label = lomac_externalize_label,
+ .mpo_pipe_init_label = lomac_init_label,
+ .mpo_pipe_internalize_label = lomac_internalize_label,
+ .mpo_pipe_relabel = lomac_pipe_relabel,
+
+ .mpo_priv_check = lomac_priv_check,
+
+ .mpo_proc_check_debug = lomac_proc_check_debug,
+ .mpo_proc_check_sched = lomac_proc_check_sched,
+ .mpo_proc_check_signal = lomac_proc_check_signal,
+ .mpo_proc_destroy_label = lomac_proc_destroy_label,
+ .mpo_proc_init_label = lomac_proc_init_label,
+
+ .mpo_socket_check_deliver = lomac_socket_check_deliver,
+ .mpo_socket_check_relabel = lomac_socket_check_relabel,
+ .mpo_socket_check_visible = lomac_socket_check_visible,
+ .mpo_socket_copy_label = lomac_copy_label,
+ .mpo_socket_create = lomac_socket_create,
+ .mpo_socket_create_mbuf = lomac_socket_create_mbuf,
+ .mpo_socket_destroy_label = lomac_destroy_label,
+ .mpo_socket_externalize_label = lomac_externalize_label,
+ .mpo_socket_init_label = lomac_init_label_waitcheck,
+ .mpo_socket_internalize_label = lomac_internalize_label,
+ .mpo_socket_newconn = lomac_socket_newconn,
+ .mpo_socket_relabel = lomac_socket_relabel,
+
+ .mpo_socketpeer_destroy_label = lomac_destroy_label,
+ .mpo_socketpeer_externalize_label = lomac_externalize_label,
+ .mpo_socketpeer_init_label = lomac_init_label_waitcheck,
+ .mpo_socketpeer_set_from_mbuf = lomac_socketpeer_set_from_mbuf,
+ .mpo_socketpeer_set_from_socket = lomac_socketpeer_set_from_socket,
+
+ .mpo_syncache_create_mbuf = lomac_syncache_create_mbuf,
+
+ .mpo_system_check_acct = lomac_system_check_acct,
+ .mpo_system_check_auditctl = lomac_system_check_auditctl,
+ .mpo_system_check_swapoff = lomac_system_check_swapoff,
+ .mpo_system_check_swapon = lomac_system_check_swapon,
+ .mpo_system_check_sysctl = lomac_system_check_sysctl,
+
+ .mpo_thread_userret = lomac_thread_userret,
+
+ .mpo_vnode_associate_extattr = lomac_vnode_associate_extattr,
+ .mpo_vnode_associate_singlelabel = lomac_vnode_associate_singlelabel,
+ .mpo_vnode_check_access = lomac_vnode_check_open,
+ .mpo_vnode_check_create = lomac_vnode_check_create,
+ .mpo_vnode_check_deleteacl = lomac_vnode_check_deleteacl,
+ .mpo_vnode_check_link = lomac_vnode_check_link,
+ .mpo_vnode_check_mmap = lomac_vnode_check_mmap,
+ .mpo_vnode_check_mmap_downgrade = lomac_vnode_check_mmap_downgrade,
+ .mpo_vnode_check_open = lomac_vnode_check_open,
+ .mpo_vnode_check_read = lomac_vnode_check_read,
+ .mpo_vnode_check_relabel = lomac_vnode_check_relabel,
+ .mpo_vnode_check_rename_from = lomac_vnode_check_rename_from,
+ .mpo_vnode_check_rename_to = lomac_vnode_check_rename_to,
+ .mpo_vnode_check_revoke = lomac_vnode_check_revoke,
+ .mpo_vnode_check_setacl = lomac_vnode_check_setacl,
+ .mpo_vnode_check_setextattr = lomac_vnode_check_setextattr,
+ .mpo_vnode_check_setflags = lomac_vnode_check_setflags,
+ .mpo_vnode_check_setmode = lomac_vnode_check_setmode,
+ .mpo_vnode_check_setowner = lomac_vnode_check_setowner,
+ .mpo_vnode_check_setutimes = lomac_vnode_check_setutimes,
+ .mpo_vnode_check_unlink = lomac_vnode_check_unlink,
+ .mpo_vnode_check_write = lomac_vnode_check_write,
+ .mpo_vnode_copy_label = lomac_copy_label,
+ .mpo_vnode_create_extattr = lomac_vnode_create_extattr,
+ .mpo_vnode_destroy_label = lomac_destroy_label,
+ .mpo_vnode_execve_transition = lomac_vnode_execve_transition,
+ .mpo_vnode_execve_will_transition = lomac_vnode_execve_will_transition,
+ .mpo_vnode_externalize_label = lomac_externalize_label,
+ .mpo_vnode_init_label = lomac_init_label,
+ .mpo_vnode_internalize_label = lomac_internalize_label,
+ .mpo_vnode_relabel = lomac_vnode_relabel,
+ .mpo_vnode_setlabel_extattr = lomac_vnode_setlabel_extattr,
+};
+
+#define LOMAC_OBJECTS (MPC_OBJECT_CRED | \
+ /* MPC_OBJECT_PROC | */ \
+ MPC_OBJECT_VNODE | \
+ MPC_OBJECT_INPCB | \
+ MPC_OBJECT_SOCKET | \
+ MPC_OBJECT_DEVFS | \
+ MPC_OBJECT_MBUF | \
+ MPC_OBJECT_IPQ | \
+ MPC_OBJECT_IFNET | \
+ MPC_OBJECT_BPFDESC | \
+ MPC_OBJECT_PIPE | \
+ MPC_OBJECT_MOUNT | \
+ /* MPC_OBJECT_POSIXSEM | */ \
+ /* MPC_OBJECT_POSIXSHM | */ \
+ /* MPC_OBJECT_SYSVMSG | */ \
+ /* MPC_OBJECT_SYSVMSQ | */ \
+ /* MPC_OBJECT_SYSVSEM | */ \
+ /* MPC_OBJECT_SYSVSHM | */ \
+ MPC_OBJECT_SYNCACHE)
+
+MAC_POLICY_SET(&lomac_ops, mac_lomac, "TrustedBSD MAC/LOMAC",
+ MPC_LOADTIME_FLAG_NOTLATE, &lomac_slot, LOMAC_OBJECTS);
diff --git a/sys/security/mac_lomac/mac_lomac.h b/sys/security/mac_lomac/mac_lomac.h
new file mode 100644
index 0000000..9edba98
--- /dev/null
+++ b/sys/security/mac_lomac/mac_lomac.h
@@ -0,0 +1,89 @@
+/*-
+ * Copyright (c) 1999-2002 Robert N. M. Watson
+ * Copyright (c) 2001-2002 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * This software was developed by Robert Watson for the TrustedBSD Project.
+ *
+ * This software was developed for the FreeBSD Project in part by NAI Labs,
+ * the Security Research Division of Network Associates, Inc. under
+ * DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA
+ * CHATS research program.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+/*
+ * Definitions for the TrustedBSD LOMAC integrity policy module.
+ */
+#ifndef _SYS_SECURITY_MAC_LOMAC_H
+#define _SYS_SECURITY_MAC_LOMAC_H
+
+#define MAC_LOMAC_EXTATTR_NAMESPACE EXTATTR_NAMESPACE_SYSTEM
+#define MAC_LOMAC_EXTATTR_NAME "mac_lomac"
+
+#define MAC_LOMAC_LABEL_NAME "lomac"
+
+#define MAC_LOMAC_FLAG_SINGLE 0x00000001 /* ml_single initialized */
+#define MAC_LOMAC_FLAG_RANGE 0x00000002 /* ml_range* initialized */
+#define MAC_LOMAC_FLAG_AUX 0x00000004 /* ml_auxsingle initialized */
+#define MAC_LOMAC_FLAGS_BOTH (MAC_LOMAC_FLAG_SINGLE | MAC_LOMAC_FLAG_RANGE)
+#define MAC_LOMAC_FLAG_UPDATE 0x00000008 /* must demote this process */
+
+#define MAC_LOMAC_TYPE_UNDEF 0 /* Undefined */
+#define MAC_LOMAC_TYPE_GRADE 1 /* Hierarchal grade with mb_grade. */
+#define MAC_LOMAC_TYPE_LOW 2 /* Dominated by any
+ * MAC_LOMAC_TYPE_LABEL. */
+#define MAC_LOMAC_TYPE_HIGH 3 /* Dominates any
+ * MAC_LOMAC_TYPE_LABEL. */
+#define MAC_LOMAC_TYPE_EQUAL 4 /* Equivilent to any
+ * MAC_LOMAC_TYPE_LABEL. */
+
+/*
+ * Structures and constants associated with a LOMAC Integrity policy.
+ * mac_lomac represents a LOMAC label, with mb_type determining its properties,
+ * and mb_grade represents the hierarchal grade if valid for the current
+ * mb_type.
+ */
+
+struct mac_lomac_element {
+ u_short mle_type;
+ u_short mle_grade;
+};
+
+/*
+ * LOMAC labels start with two components: a single label, and a label
+ * range. Depending on the context, one or both may be used; the ml_flags
+ * field permits the provider to indicate what fields are intended for
+ * use. The auxiliary label works the same way, but is only valid on
+ * filesystem objects to provide inheritance semantics on directories
+ * and "non-demoting" execution on executable files.
+ */
+struct mac_lomac {
+ int ml_flags;
+ struct mac_lomac_element ml_single;
+ struct mac_lomac_element ml_rangelow, ml_rangehigh;
+ struct mac_lomac_element ml_auxsingle;
+};
+
+#endif /* !_SYS_SECURITY_MAC_LOMAC_H */
diff --git a/sys/security/mac_mls/mac_mls.c b/sys/security/mac_mls/mac_mls.c
new file mode 100644
index 0000000..217fa5f
--- /dev/null
+++ b/sys/security/mac_mls/mac_mls.c
@@ -0,0 +1,3186 @@
+/*-
+ * Copyright (c) 1999-2002, 2007-2008 Robert N. M. Watson
+ * Copyright (c) 2001-2005 McAfee, Inc.
+ * Copyright (c) 2006 SPARTA, Inc.
+ * All rights reserved.
+ *
+ * This software was developed by Robert Watson for the TrustedBSD Project.
+ *
+ * This software was developed for the FreeBSD Project in part by McAfee
+ * Research, the Security Research Division of McAfee, Inc. under
+ * DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA
+ * CHATS research program.
+ *
+ * This software was enhanced by SPARTA ISSO under SPAWAR contract
+ * N66001-04-C-6019 ("SEFOS").
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Developed by the TrustedBSD Project.
+ *
+ * MLS fixed label mandatory confidentiality policy.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/acl.h>
+#include <sys/conf.h>
+#include <sys/extattr.h>
+#include <sys/kernel.h>
+#include <sys/ksem.h>
+#include <sys/mman.h>
+#include <sys/malloc.h>
+#include <sys/mount.h>
+#include <sys/proc.h>
+#include <sys/sbuf.h>
+#include <sys/systm.h>
+#include <sys/sysproto.h>
+#include <sys/sysent.h>
+#include <sys/systm.h>
+#include <sys/vnode.h>
+#include <sys/file.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/pipe.h>
+#include <sys/sx.h>
+#include <sys/sysctl.h>
+#include <sys/msg.h>
+#include <sys/sem.h>
+#include <sys/shm.h>
+
+#include <fs/devfs/devfs.h>
+
+#include <net/bpfdesc.h>
+#include <net/if.h>
+#include <net/if_types.h>
+#include <net/if_var.h>
+
+#include <netinet/in.h>
+#include <netinet/in_pcb.h>
+#include <netinet/ip_var.h>
+
+#include <vm/uma.h>
+#include <vm/vm.h>
+
+#include <security/mac/mac_policy.h>
+#include <security/mac_mls/mac_mls.h>
+
+SYSCTL_DECL(_security_mac);
+
+SYSCTL_NODE(_security_mac, OID_AUTO, mls, CTLFLAG_RW, 0,
+ "TrustedBSD mac_mls policy controls");
+
+static int mls_label_size = sizeof(struct mac_mls);
+SYSCTL_INT(_security_mac_mls, OID_AUTO, label_size, CTLFLAG_RD,
+ &mls_label_size, 0, "Size of struct mac_mls");
+
+static int mls_enabled = 1;
+SYSCTL_INT(_security_mac_mls, OID_AUTO, enabled, CTLFLAG_RW, &mls_enabled, 0,
+ "Enforce MAC/MLS policy");
+TUNABLE_INT("security.mac.mls.enabled", &mls_enabled);
+
+static int destroyed_not_inited;
+SYSCTL_INT(_security_mac_mls, OID_AUTO, destroyed_not_inited, CTLFLAG_RD,
+ &destroyed_not_inited, 0, "Count of labels destroyed but not inited");
+
+static int ptys_equal = 0;
+SYSCTL_INT(_security_mac_mls, OID_AUTO, ptys_equal, CTLFLAG_RW,
+ &ptys_equal, 0, "Label pty devices as mls/equal on create");
+TUNABLE_INT("security.mac.mls.ptys_equal", &ptys_equal);
+
+static int revocation_enabled = 0;
+SYSCTL_INT(_security_mac_mls, OID_AUTO, revocation_enabled, CTLFLAG_RW,
+ &revocation_enabled, 0, "Revoke access to objects on relabel");
+TUNABLE_INT("security.mac.mls.revocation_enabled", &revocation_enabled);
+
+static int max_compartments = MAC_MLS_MAX_COMPARTMENTS;
+SYSCTL_INT(_security_mac_mls, OID_AUTO, max_compartments, CTLFLAG_RD,
+ &max_compartments, 0, "Maximum compartments the policy supports");
+
+static int mls_slot;
+#define SLOT(l) ((struct mac_mls *)mac_label_get((l), mls_slot))
+#define SLOT_SET(l, val) mac_label_set((l), mls_slot, (uintptr_t)(val))
+
+static uma_zone_t zone_mls;
+
+static __inline int
+mls_bit_set_empty(u_char *set) {
+ int i;
+
+ for (i = 0; i < MAC_MLS_MAX_COMPARTMENTS >> 3; i++)
+ if (set[i] != 0)
+ return (0);
+ return (1);
+}
+
+static struct mac_mls *
+mls_alloc(int flag)
+{
+
+ return (uma_zalloc(zone_mls, flag | M_ZERO));
+}
+
+static void
+mls_free(struct mac_mls *mm)
+{
+
+ if (mm != NULL)
+ uma_zfree(zone_mls, mm);
+ else
+ atomic_add_int(&destroyed_not_inited, 1);
+}
+
+static int
+mls_atmostflags(struct mac_mls *mm, int flags)
+{
+
+ if ((mm->mm_flags & flags) != mm->mm_flags)
+ return (EINVAL);
+ return (0);
+}
+
+static int
+mls_dominate_element(struct mac_mls_element *a, struct mac_mls_element *b)
+{
+ int bit;
+
+ switch (a->mme_type) {
+ case MAC_MLS_TYPE_EQUAL:
+ case MAC_MLS_TYPE_HIGH:
+ return (1);
+
+ case MAC_MLS_TYPE_LOW:
+ switch (b->mme_type) {
+ case MAC_MLS_TYPE_LEVEL:
+ case MAC_MLS_TYPE_HIGH:
+ return (0);
+
+ case MAC_MLS_TYPE_EQUAL:
+ case MAC_MLS_TYPE_LOW:
+ return (1);
+
+ default:
+ panic("mls_dominate_element: b->mme_type invalid");
+ }
+
+ case MAC_MLS_TYPE_LEVEL:
+ switch (b->mme_type) {
+ case MAC_MLS_TYPE_EQUAL:
+ case MAC_MLS_TYPE_LOW:
+ return (1);
+
+ case MAC_MLS_TYPE_HIGH:
+ return (0);
+
+ case MAC_MLS_TYPE_LEVEL:
+ for (bit = 1; bit <= MAC_MLS_MAX_COMPARTMENTS; bit++)
+ if (!MAC_MLS_BIT_TEST(bit,
+ a->mme_compartments) &&
+ MAC_MLS_BIT_TEST(bit, b->mme_compartments))
+ return (0);
+ return (a->mme_level >= b->mme_level);
+
+ default:
+ panic("mls_dominate_element: b->mme_type invalid");
+ }
+
+ default:
+ panic("mls_dominate_element: a->mme_type invalid");
+ }
+
+ return (0);
+}
+
+static int
+mls_range_in_range(struct mac_mls *rangea, struct mac_mls *rangeb)
+{
+
+ return (mls_dominate_element(&rangeb->mm_rangehigh,
+ &rangea->mm_rangehigh) &&
+ mls_dominate_element(&rangea->mm_rangelow,
+ &rangeb->mm_rangelow));
+}
+
+static int
+mls_effective_in_range(struct mac_mls *effective, struct mac_mls *range)
+{
+
+ KASSERT((effective->mm_flags & MAC_MLS_FLAG_EFFECTIVE) != 0,
+ ("mls_effective_in_range: a not effective"));
+ KASSERT((range->mm_flags & MAC_MLS_FLAG_RANGE) != 0,
+ ("mls_effective_in_range: b not range"));
+
+ return (mls_dominate_element(&range->mm_rangehigh,
+ &effective->mm_effective) &&
+ mls_dominate_element(&effective->mm_effective,
+ &range->mm_rangelow));
+
+ return (1);
+}
+
+static int
+mls_dominate_effective(struct mac_mls *a, struct mac_mls *b)
+{
+ KASSERT((a->mm_flags & MAC_MLS_FLAG_EFFECTIVE) != 0,
+ ("mls_dominate_effective: a not effective"));
+ KASSERT((b->mm_flags & MAC_MLS_FLAG_EFFECTIVE) != 0,
+ ("mls_dominate_effective: b not effective"));
+
+ return (mls_dominate_element(&a->mm_effective, &b->mm_effective));
+}
+
+static int
+mls_equal_element(struct mac_mls_element *a, struct mac_mls_element *b)
+{
+
+ if (a->mme_type == MAC_MLS_TYPE_EQUAL ||
+ b->mme_type == MAC_MLS_TYPE_EQUAL)
+ return (1);
+
+ return (a->mme_type == b->mme_type && a->mme_level == b->mme_level);
+}
+
+static int
+mls_equal_effective(struct mac_mls *a, struct mac_mls *b)
+{
+
+ KASSERT((a->mm_flags & MAC_MLS_FLAG_EFFECTIVE) != 0,
+ ("mls_equal_effective: a not effective"));
+ KASSERT((b->mm_flags & MAC_MLS_FLAG_EFFECTIVE) != 0,
+ ("mls_equal_effective: b not effective"));
+
+ return (mls_equal_element(&a->mm_effective, &b->mm_effective));
+}
+
+static int
+mls_contains_equal(struct mac_mls *mm)
+{
+
+ if (mm->mm_flags & MAC_MLS_FLAG_EFFECTIVE)
+ if (mm->mm_effective.mme_type == MAC_MLS_TYPE_EQUAL)
+ return (1);
+
+ if (mm->mm_flags & MAC_MLS_FLAG_RANGE) {
+ if (mm->mm_rangelow.mme_type == MAC_MLS_TYPE_EQUAL)
+ return (1);
+ if (mm->mm_rangehigh.mme_type == MAC_MLS_TYPE_EQUAL)
+ return (1);
+ }
+
+ return (0);
+}
+
+static int
+mls_subject_privileged(struct mac_mls *mm)
+{
+
+ KASSERT((mm->mm_flags & MAC_MLS_FLAGS_BOTH) == MAC_MLS_FLAGS_BOTH,
+ ("mls_subject_privileged: subject doesn't have both labels"));
+
+ /* If the effective is EQUAL, it's ok. */
+ if (mm->mm_effective.mme_type == MAC_MLS_TYPE_EQUAL)
+ return (0);
+
+ /* If either range endpoint is EQUAL, it's ok. */
+ if (mm->mm_rangelow.mme_type == MAC_MLS_TYPE_EQUAL ||
+ mm->mm_rangehigh.mme_type == MAC_MLS_TYPE_EQUAL)
+ return (0);
+
+ /* If the range is low-high, it's ok. */
+ if (mm->mm_rangelow.mme_type == MAC_MLS_TYPE_LOW &&
+ mm->mm_rangehigh.mme_type == MAC_MLS_TYPE_HIGH)
+ return (0);
+
+ /* It's not ok. */
+ return (EPERM);
+}
+
+static int
+mls_valid(struct mac_mls *mm)
+{
+
+ if (mm->mm_flags & MAC_MLS_FLAG_EFFECTIVE) {
+ switch (mm->mm_effective.mme_type) {
+ case MAC_MLS_TYPE_LEVEL:
+ break;
+
+ case MAC_MLS_TYPE_EQUAL:
+ case MAC_MLS_TYPE_HIGH:
+ case MAC_MLS_TYPE_LOW:
+ if (mm->mm_effective.mme_level != 0 ||
+ !MAC_MLS_BIT_SET_EMPTY(
+ mm->mm_effective.mme_compartments))
+ return (EINVAL);
+ break;
+
+ default:
+ return (EINVAL);
+ }
+ } else {
+ if (mm->mm_effective.mme_type != MAC_MLS_TYPE_UNDEF)
+ return (EINVAL);
+ }
+
+ if (mm->mm_flags & MAC_MLS_FLAG_RANGE) {
+ switch (mm->mm_rangelow.mme_type) {
+ case MAC_MLS_TYPE_LEVEL:
+ break;
+
+ case MAC_MLS_TYPE_EQUAL:
+ case MAC_MLS_TYPE_HIGH:
+ case MAC_MLS_TYPE_LOW:
+ if (mm->mm_rangelow.mme_level != 0 ||
+ !MAC_MLS_BIT_SET_EMPTY(
+ mm->mm_rangelow.mme_compartments))
+ return (EINVAL);
+ break;
+
+ default:
+ return (EINVAL);
+ }
+
+ switch (mm->mm_rangehigh.mme_type) {
+ case MAC_MLS_TYPE_LEVEL:
+ break;
+
+ case MAC_MLS_TYPE_EQUAL:
+ case MAC_MLS_TYPE_HIGH:
+ case MAC_MLS_TYPE_LOW:
+ if (mm->mm_rangehigh.mme_level != 0 ||
+ !MAC_MLS_BIT_SET_EMPTY(
+ mm->mm_rangehigh.mme_compartments))
+ return (EINVAL);
+ break;
+
+ default:
+ return (EINVAL);
+ }
+ if (!mls_dominate_element(&mm->mm_rangehigh,
+ &mm->mm_rangelow))
+ return (EINVAL);
+ } else {
+ if (mm->mm_rangelow.mme_type != MAC_MLS_TYPE_UNDEF ||
+ mm->mm_rangehigh.mme_type != MAC_MLS_TYPE_UNDEF)
+ return (EINVAL);
+ }
+
+ return (0);
+}
+
+static void
+mls_set_range(struct mac_mls *mm, u_short typelow, u_short levellow,
+ u_char *compartmentslow, u_short typehigh, u_short levelhigh,
+ u_char *compartmentshigh)
+{
+
+ mm->mm_rangelow.mme_type = typelow;
+ mm->mm_rangelow.mme_level = levellow;
+ if (compartmentslow != NULL)
+ memcpy(mm->mm_rangelow.mme_compartments, compartmentslow,
+ sizeof(mm->mm_rangelow.mme_compartments));
+ mm->mm_rangehigh.mme_type = typehigh;
+ mm->mm_rangehigh.mme_level = levelhigh;
+ if (compartmentshigh != NULL)
+ memcpy(mm->mm_rangehigh.mme_compartments, compartmentshigh,
+ sizeof(mm->mm_rangehigh.mme_compartments));
+ mm->mm_flags |= MAC_MLS_FLAG_RANGE;
+}
+
+static void
+mls_set_effective(struct mac_mls *mm, u_short type, u_short level,
+ u_char *compartments)
+{
+
+ mm->mm_effective.mme_type = type;
+ mm->mm_effective.mme_level = level;
+ if (compartments != NULL)
+ memcpy(mm->mm_effective.mme_compartments, compartments,
+ sizeof(mm->mm_effective.mme_compartments));
+ mm->mm_flags |= MAC_MLS_FLAG_EFFECTIVE;
+}
+
+static void
+mls_copy_range(struct mac_mls *labelfrom, struct mac_mls *labelto)
+{
+
+ KASSERT((labelfrom->mm_flags & MAC_MLS_FLAG_RANGE) != 0,
+ ("mls_copy_range: labelfrom not range"));
+
+ labelto->mm_rangelow = labelfrom->mm_rangelow;
+ labelto->mm_rangehigh = labelfrom->mm_rangehigh;
+ labelto->mm_flags |= MAC_MLS_FLAG_RANGE;
+}
+
+static void
+mls_copy_effective(struct mac_mls *labelfrom, struct mac_mls *labelto)
+{
+
+ KASSERT((labelfrom->mm_flags & MAC_MLS_FLAG_EFFECTIVE) != 0,
+ ("mls_copy_effective: labelfrom not effective"));
+
+ labelto->mm_effective = labelfrom->mm_effective;
+ labelto->mm_flags |= MAC_MLS_FLAG_EFFECTIVE;
+}
+
+static void
+mls_copy(struct mac_mls *source, struct mac_mls *dest)
+{
+
+ if (source->mm_flags & MAC_MLS_FLAG_EFFECTIVE)
+ mls_copy_effective(source, dest);
+ if (source->mm_flags & MAC_MLS_FLAG_RANGE)
+ mls_copy_range(source, dest);
+}
+
+/*
+ * Policy module operations.
+ */
+static void
+mls_init(struct mac_policy_conf *conf)
+{
+
+ zone_mls = uma_zcreate("mac_mls", sizeof(struct mac_mls), NULL,
+ NULL, NULL, NULL, UMA_ALIGN_PTR, 0);
+}
+
+/*
+ * Label operations.
+ */
+static void
+mls_init_label(struct label *label)
+{
+
+ SLOT_SET(label, mls_alloc(M_WAITOK));
+}
+
+static int
+mls_init_label_waitcheck(struct label *label, int flag)
+{
+
+ SLOT_SET(label, mls_alloc(flag));
+ if (SLOT(label) == NULL)
+ return (ENOMEM);
+
+ return (0);
+}
+
+static void
+mls_destroy_label(struct label *label)
+{
+
+ mls_free(SLOT(label));
+ SLOT_SET(label, NULL);
+}
+
+/*
+ * mls_element_to_string() accepts an sbuf and MLS element. It converts the
+ * MLS element to a string and stores the result in the sbuf; if there isn't
+ * space in the sbuf, -1 is returned.
+ */
+static int
+mls_element_to_string(struct sbuf *sb, struct mac_mls_element *element)
+{
+ int i, first;
+
+ switch (element->mme_type) {
+ case MAC_MLS_TYPE_HIGH:
+ return (sbuf_printf(sb, "high"));
+
+ case MAC_MLS_TYPE_LOW:
+ return (sbuf_printf(sb, "low"));
+
+ case MAC_MLS_TYPE_EQUAL:
+ return (sbuf_printf(sb, "equal"));
+
+ case MAC_MLS_TYPE_LEVEL:
+ if (sbuf_printf(sb, "%d", element->mme_level) == -1)
+ return (-1);
+
+ first = 1;
+ for (i = 1; i <= MAC_MLS_MAX_COMPARTMENTS; i++) {
+ if (MAC_MLS_BIT_TEST(i, element->mme_compartments)) {
+ if (first) {
+ if (sbuf_putc(sb, ':') == -1)
+ return (-1);
+ if (sbuf_printf(sb, "%d", i) == -1)
+ return (-1);
+ first = 0;
+ } else {
+ if (sbuf_printf(sb, "+%d", i) == -1)
+ return (-1);
+ }
+ }
+ }
+ return (0);
+
+ default:
+ panic("mls_element_to_string: invalid type (%d)",
+ element->mme_type);
+ }
+}
+
+/*
+ * mls_to_string() converts an MLS label to a string, and places the results
+ * in the passed sbuf. It returns 0 on success, or EINVAL if there isn't
+ * room in the sbuf. Note: the sbuf will be modified even in a failure case,
+ * so the caller may need to revert the sbuf by restoring the offset if
+ * that's undesired.
+ */
+static int
+mls_to_string(struct sbuf *sb, struct mac_mls *mm)
+{
+
+ if (mm->mm_flags & MAC_MLS_FLAG_EFFECTIVE) {
+ if (mls_element_to_string(sb, &mm->mm_effective) == -1)
+ return (EINVAL);
+ }
+
+ if (mm->mm_flags & MAC_MLS_FLAG_RANGE) {
+ if (sbuf_putc(sb, '(') == -1)
+ return (EINVAL);
+
+ if (mls_element_to_string(sb, &mm->mm_rangelow) == -1)
+ return (EINVAL);
+
+ if (sbuf_putc(sb, '-') == -1)
+ return (EINVAL);
+
+ if (mls_element_to_string(sb, &mm->mm_rangehigh) == -1)
+ return (EINVAL);
+
+ if (sbuf_putc(sb, ')') == -1)
+ return (EINVAL);
+ }
+
+ return (0);
+}
+
+static int
+mls_externalize_label(struct label *label, char *element_name,
+ struct sbuf *sb, int *claimed)
+{
+ struct mac_mls *mm;
+
+ if (strcmp(MAC_MLS_LABEL_NAME, element_name) != 0)
+ return (0);
+
+ (*claimed)++;
+
+ mm = SLOT(label);
+
+ return (mls_to_string(sb, mm));
+}
+
+static int
+mls_parse_element(struct mac_mls_element *element, char *string)
+{
+ char *compartment, *end, *level;
+ int value;
+
+ if (strcmp(string, "high") == 0 || strcmp(string, "hi") == 0) {
+ element->mme_type = MAC_MLS_TYPE_HIGH;
+ element->mme_level = MAC_MLS_TYPE_UNDEF;
+ } else if (strcmp(string, "low") == 0 || strcmp(string, "lo") == 0) {
+ element->mme_type = MAC_MLS_TYPE_LOW;
+ element->mme_level = MAC_MLS_TYPE_UNDEF;
+ } else if (strcmp(string, "equal") == 0 ||
+ strcmp(string, "eq") == 0) {
+ element->mme_type = MAC_MLS_TYPE_EQUAL;
+ element->mme_level = MAC_MLS_TYPE_UNDEF;
+ } else {
+ element->mme_type = MAC_MLS_TYPE_LEVEL;
+
+ /*
+ * Numeric level piece of the element.
+ */
+ level = strsep(&string, ":");
+ value = strtol(level, &end, 10);
+ if (end == level || *end != '\0')
+ return (EINVAL);
+ if (value < 0 || value > 65535)
+ return (EINVAL);
+ element->mme_level = value;
+
+ /*
+ * Optional compartment piece of the element. If none are
+ * included, we assume that the label has no compartments.
+ */
+ if (string == NULL)
+ return (0);
+ if (*string == '\0')
+ return (0);
+
+ while ((compartment = strsep(&string, "+")) != NULL) {
+ value = strtol(compartment, &end, 10);
+ if (compartment == end || *end != '\0')
+ return (EINVAL);
+ if (value < 1 || value > MAC_MLS_MAX_COMPARTMENTS)
+ return (EINVAL);
+ MAC_MLS_BIT_SET(value, element->mme_compartments);
+ }
+ }
+
+ return (0);
+}
+
+/*
+ * Note: destructively consumes the string, make a local copy before calling
+ * if that's a problem.
+ */
+static int
+mls_parse(struct mac_mls *mm, char *string)
+{
+ char *rangehigh, *rangelow, *effective;
+ int error;
+
+ effective = strsep(&string, "(");
+ if (*effective == '\0')
+ effective = NULL;
+
+ if (string != NULL) {
+ rangelow = strsep(&string, "-");
+ if (string == NULL)
+ return (EINVAL);
+ rangehigh = strsep(&string, ")");
+ if (string == NULL)
+ return (EINVAL);
+ if (*string != '\0')
+ return (EINVAL);
+ } else {
+ rangelow = NULL;
+ rangehigh = NULL;
+ }
+
+ KASSERT((rangelow != NULL && rangehigh != NULL) ||
+ (rangelow == NULL && rangehigh == NULL),
+ ("mls_parse: range mismatch"));
+
+ bzero(mm, sizeof(*mm));
+ if (effective != NULL) {
+ error = mls_parse_element(&mm->mm_effective, effective);
+ if (error)
+ return (error);
+ mm->mm_flags |= MAC_MLS_FLAG_EFFECTIVE;
+ }
+
+ if (rangelow != NULL) {
+ error = mls_parse_element(&mm->mm_rangelow, rangelow);
+ if (error)
+ return (error);
+ error = mls_parse_element(&mm->mm_rangehigh, rangehigh);
+ if (error)
+ return (error);
+ mm->mm_flags |= MAC_MLS_FLAG_RANGE;
+ }
+
+ error = mls_valid(mm);
+ if (error)
+ return (error);
+
+ return (0);
+}
+
+static int
+mls_internalize_label(struct label *label, char *element_name,
+ char *element_data, int *claimed)
+{
+ struct mac_mls *mm, mm_temp;
+ int error;
+
+ if (strcmp(MAC_MLS_LABEL_NAME, element_name) != 0)
+ return (0);
+
+ (*claimed)++;
+
+ error = mls_parse(&mm_temp, element_data);
+ if (error)
+ return (error);
+
+ mm = SLOT(label);
+ *mm = mm_temp;
+
+ return (0);
+}
+
+static void
+mls_copy_label(struct label *src, struct label *dest)
+{
+
+ *SLOT(dest) = *SLOT(src);
+}
+
+/*
+ * Object-specific entry point implementations are sorted alphabetically by
+ * object type name and then by operation.
+ */
+static int
+mls_bpfdesc_check_receive(struct bpf_d *d, struct label *dlabel,
+ struct ifnet *ifp, struct label *ifplabel)
+{
+ struct mac_mls *a, *b;
+
+ if (!mls_enabled)
+ return (0);
+
+ a = SLOT(dlabel);
+ b = SLOT(ifplabel);
+
+ if (mls_equal_effective(a, b))
+ return (0);
+ return (EACCES);
+}
+
+static void
+mls_bpfdesc_create(struct ucred *cred, struct bpf_d *d, struct label *dlabel)
+{
+ struct mac_mls *source, *dest;
+
+ source = SLOT(cred->cr_label);
+ dest = SLOT(dlabel);
+
+ mls_copy_effective(source, dest);
+}
+
+static void
+mls_bpfdesc_create_mbuf(struct bpf_d *d, struct label *dlabel,
+ struct mbuf *m, struct label *mlabel)
+{
+ struct mac_mls *source, *dest;
+
+ source = SLOT(dlabel);
+ dest = SLOT(mlabel);
+
+ mls_copy_effective(source, dest);
+}
+
+static void
+mls_cred_associate_nfsd(struct ucred *cred)
+{
+ struct mac_mls *label;
+
+ label = SLOT(cred->cr_label);
+ mls_set_effective(label, MAC_MLS_TYPE_LOW, 0, NULL);
+ mls_set_range(label, MAC_MLS_TYPE_LOW, 0, NULL, MAC_MLS_TYPE_HIGH, 0,
+ NULL);
+}
+
+static int
+mls_cred_check_relabel(struct ucred *cred, struct label *newlabel)
+{
+ struct mac_mls *subj, *new;
+ int error;
+
+ subj = SLOT(cred->cr_label);
+ new = SLOT(newlabel);
+
+ /*
+ * If there is an MLS label update for the credential, it may be an
+ * update of effective, range, or both.
+ */
+ error = mls_atmostflags(new, MAC_MLS_FLAGS_BOTH);
+ if (error)
+ return (error);
+
+ /*
+ * If the MLS label is to be changed, authorize as appropriate.
+ */
+ if (new->mm_flags & MAC_MLS_FLAGS_BOTH) {
+ /*
+ * If the change request modifies both the MLS label
+ * effective and range, check that the new effective will be
+ * in the new range.
+ */
+ if ((new->mm_flags & MAC_MLS_FLAGS_BOTH) ==
+ MAC_MLS_FLAGS_BOTH && !mls_effective_in_range(new, new))
+ return (EINVAL);
+
+ /*
+ * To change the MLS effective label on a credential, the new
+ * effective label must be in the current range.
+ */
+ if (new->mm_flags & MAC_MLS_FLAG_EFFECTIVE &&
+ !mls_effective_in_range(new, subj))
+ return (EPERM);
+
+ /*
+ * To change the MLS range label on a credential, the new
+ * range must be in the current range.
+ */
+ if (new->mm_flags & MAC_MLS_FLAG_RANGE &&
+ !mls_range_in_range(new, subj))
+ return (EPERM);
+
+ /*
+ * To have EQUAL in any component of the new credential MLS
+ * label, the subject must already have EQUAL in their label.
+ */
+ if (mls_contains_equal(new)) {
+ error = mls_subject_privileged(subj);
+ if (error)
+ return (error);
+ }
+ }
+
+ return (0);
+}
+
+static int
+mls_cred_check_visible(struct ucred *cr1, struct ucred *cr2)
+{
+ struct mac_mls *subj, *obj;
+
+ if (!mls_enabled)
+ return (0);
+
+ subj = SLOT(cr1->cr_label);
+ obj = SLOT(cr2->cr_label);
+
+ /* XXX: range */
+ if (!mls_dominate_effective(subj, obj))
+ return (ESRCH);
+
+ return (0);
+}
+
+static void
+mls_cred_create_init(struct ucred *cred)
+{
+ struct mac_mls *dest;
+
+ dest = SLOT(cred->cr_label);
+
+ mls_set_effective(dest, MAC_MLS_TYPE_LOW, 0, NULL);
+ mls_set_range(dest, MAC_MLS_TYPE_LOW, 0, NULL, MAC_MLS_TYPE_HIGH, 0,
+ NULL);
+}
+
+static void
+mls_cred_create_swapper(struct ucred *cred)
+{
+ struct mac_mls *dest;
+
+ dest = SLOT(cred->cr_label);
+
+ mls_set_effective(dest, MAC_MLS_TYPE_EQUAL, 0, NULL);
+ mls_set_range(dest, MAC_MLS_TYPE_LOW, 0, NULL, MAC_MLS_TYPE_HIGH, 0,
+ NULL);
+}
+
+static void
+mls_cred_relabel(struct ucred *cred, struct label *newlabel)
+{
+ struct mac_mls *source, *dest;
+
+ source = SLOT(newlabel);
+ dest = SLOT(cred->cr_label);
+
+ mls_copy(source, dest);
+}
+
+static void
+mls_devfs_create_device(struct ucred *cred, struct mount *mp,
+ struct cdev *dev, struct devfs_dirent *de, struct label *delabel)
+{
+ struct mac_mls *mm;
+ int mls_type;
+
+ mm = SLOT(delabel);
+ if (strcmp(dev->si_name, "null") == 0 ||
+ strcmp(dev->si_name, "zero") == 0 ||
+ strcmp(dev->si_name, "random") == 0 ||
+ strncmp(dev->si_name, "fd/", strlen("fd/")) == 0)
+ mls_type = MAC_MLS_TYPE_EQUAL;
+ else if (strcmp(dev->si_name, "kmem") == 0 ||
+ strcmp(dev->si_name, "mem") == 0)
+ mls_type = MAC_MLS_TYPE_HIGH;
+ else if (ptys_equal &&
+ (strncmp(dev->si_name, "ttyp", strlen("ttyp")) == 0 ||
+ strncmp(dev->si_name, "ptyp", strlen("ptyp")) == 0))
+ mls_type = MAC_MLS_TYPE_EQUAL;
+ else
+ mls_type = MAC_MLS_TYPE_LOW;
+ mls_set_effective(mm, mls_type, 0, NULL);
+}
+
+static void
+mls_devfs_create_directory(struct mount *mp, char *dirname, int dirnamelen,
+ struct devfs_dirent *de, struct label *delabel)
+{
+ struct mac_mls *mm;
+
+ mm = SLOT(delabel);
+ mls_set_effective(mm, MAC_MLS_TYPE_LOW, 0, NULL);
+}
+
+static void
+mls_devfs_create_symlink(struct ucred *cred, struct mount *mp,
+ struct devfs_dirent *dd, struct label *ddlabel, struct devfs_dirent *de,
+ struct label *delabel)
+{
+ struct mac_mls *source, *dest;
+
+ source = SLOT(cred->cr_label);
+ dest = SLOT(delabel);
+
+ mls_copy_effective(source, dest);
+}
+
+static void
+mls_devfs_update(struct mount *mp, struct devfs_dirent *de,
+ struct label *delabel, struct vnode *vp, struct label *vplabel)
+{
+ struct mac_mls *source, *dest;
+
+ source = SLOT(vplabel);
+ dest = SLOT(delabel);
+
+ mls_copy_effective(source, dest);
+}
+
+static void
+mls_devfs_vnode_associate(struct mount *mp, struct label *mplabel,
+ struct devfs_dirent *de, struct label *delabel, struct vnode *vp,
+ struct label *vplabel)
+{
+ struct mac_mls *source, *dest;
+
+ source = SLOT(delabel);
+ dest = SLOT(vplabel);
+
+ mls_copy_effective(source, dest);
+}
+
+static int
+mls_ifnet_check_relabel(struct ucred *cred, struct ifnet *ifp,
+ struct label *ifplabel, struct label *newlabel)
+{
+ struct mac_mls *subj, *new;
+ int error;
+
+ subj = SLOT(cred->cr_label);
+ new = SLOT(newlabel);
+
+ /*
+ * If there is an MLS label update for the interface, it may be an
+ * update of effective, range, or both.
+ */
+ error = mls_atmostflags(new, MAC_MLS_FLAGS_BOTH);
+ if (error)
+ return (error);
+
+ /*
+ * Relabeling network interfaces requires MLS privilege.
+ */
+ return (mls_subject_privileged(subj));
+}
+
+static int
+mls_ifnet_check_transmit(struct ifnet *ifp, struct label *ifplabel,
+ struct mbuf *m, struct label *mlabel)
+{
+ struct mac_mls *p, *i;
+
+ if (!mls_enabled)
+ return (0);
+
+ p = SLOT(mlabel);
+ i = SLOT(ifplabel);
+
+ return (mls_effective_in_range(p, i) ? 0 : EACCES);
+}
+
+static void
+mls_ifnet_create(struct ifnet *ifp, struct label *ifplabel)
+{
+ struct mac_mls *dest;
+ int type;
+
+ dest = SLOT(ifplabel);
+
+ if (ifp->if_type == IFT_LOOP)
+ type = MAC_MLS_TYPE_EQUAL;
+ else
+ type = MAC_MLS_TYPE_LOW;
+
+ mls_set_effective(dest, type, 0, NULL);
+ mls_set_range(dest, type, 0, NULL, type, 0, NULL);
+}
+
+static void
+mls_ifnet_create_mbuf(struct ifnet *ifp, struct label *ifplabel,
+ struct mbuf *m, struct label *mlabel)
+{
+ struct mac_mls *source, *dest;
+
+ source = SLOT(ifplabel);
+ dest = SLOT(mlabel);
+
+ mls_copy_effective(source, dest);
+}
+
+static void
+mls_ifnet_relabel(struct ucred *cred, struct ifnet *ifp,
+ struct label *ifplabel, struct label *newlabel)
+{
+ struct mac_mls *source, *dest;
+
+ source = SLOT(newlabel);
+ dest = SLOT(ifplabel);
+
+ mls_copy(source, dest);
+}
+
+static int
+mls_inpcb_check_deliver(struct inpcb *inp, struct label *inplabel,
+ struct mbuf *m, struct label *mlabel)
+{
+ struct mac_mls *p, *i;
+
+ if (!mls_enabled)
+ return (0);
+
+ p = SLOT(mlabel);
+ i = SLOT(inplabel);
+
+ return (mls_equal_effective(p, i) ? 0 : EACCES);
+}
+
+static int
+mls_inpcb_check_visible(struct ucred *cred, struct inpcb *inp,
+ struct label *inplabel)
+{
+ struct mac_mls *subj, *obj;
+
+ if (!mls_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(inplabel);
+
+ if (!mls_dominate_effective(subj, obj))
+ return (ENOENT);
+
+ return (0);
+}
+
+static void
+mls_inpcb_create(struct socket *so, struct label *solabel, struct inpcb *inp,
+ struct label *inplabel)
+{
+ struct mac_mls *source, *dest;
+
+ source = SLOT(solabel);
+ dest = SLOT(inplabel);
+
+ mls_copy_effective(source, dest);
+}
+
+static void
+mls_inpcb_create_mbuf(struct inpcb *inp, struct label *inplabel,
+ struct mbuf *m, struct label *mlabel)
+{
+ struct mac_mls *source, *dest;
+
+ source = SLOT(inplabel);
+ dest = SLOT(mlabel);
+
+ mls_copy_effective(source, dest);
+}
+
+static void
+mls_inpcb_sosetlabel(struct socket *so, struct label *solabel,
+ struct inpcb *inp, struct label *inplabel)
+{
+ struct mac_mls *source, *dest;
+
+ source = SLOT(solabel);
+ dest = SLOT(inplabel);
+
+ mls_copy(source, dest);
+}
+
+static void
+mls_ip6q_create(struct mbuf *m, struct label *mlabel, struct ip6q *q6,
+ struct label *q6label)
+{
+ struct mac_mls *source, *dest;
+
+ source = SLOT(mlabel);
+ dest = SLOT(q6label);
+
+ mls_copy_effective(source, dest);
+}
+
+static int
+mls_ip6q_match(struct mbuf *m, struct label *mlabel, struct ip6q *q6,
+ struct label *q6label)
+{
+ struct mac_mls *a, *b;
+
+ a = SLOT(q6label);
+ b = SLOT(mlabel);
+
+ return (mls_equal_effective(a, b));
+}
+
+static void
+mls_ip6q_reassemble(struct ip6q *q6, struct label *q6label, struct mbuf *m,
+ struct label *mlabel)
+{
+ struct mac_mls *source, *dest;
+
+ source = SLOT(q6label);
+ dest = SLOT(mlabel);
+
+ /* Just use the head, since we require them all to match. */
+ mls_copy_effective(source, dest);
+}
+
+static void
+mls_ip6q_update(struct mbuf *m, struct label *mlabel, struct ip6q *q6,
+ struct label *q6label)
+{
+
+ /* NOOP: we only accept matching labels, so no need to update */
+}
+
+static void
+mls_ipq_create(struct mbuf *m, struct label *mlabel, struct ipq *q,
+ struct label *qlabel)
+{
+ struct mac_mls *source, *dest;
+
+ source = SLOT(mlabel);
+ dest = SLOT(qlabel);
+
+ mls_copy_effective(source, dest);
+}
+
+static int
+mls_ipq_match(struct mbuf *m, struct label *mlabel, struct ipq *q,
+ struct label *qlabel)
+{
+ struct mac_mls *a, *b;
+
+ a = SLOT(qlabel);
+ b = SLOT(mlabel);
+
+ return (mls_equal_effective(a, b));
+}
+
+static void
+mls_ipq_reassemble(struct ipq *q, struct label *qlabel, struct mbuf *m,
+ struct label *mlabel)
+{
+ struct mac_mls *source, *dest;
+
+ source = SLOT(qlabel);
+ dest = SLOT(mlabel);
+
+ /* Just use the head, since we require them all to match. */
+ mls_copy_effective(source, dest);
+}
+
+static void
+mls_ipq_update(struct mbuf *m, struct label *mlabel, struct ipq *q,
+ struct label *qlabel)
+{
+
+ /* NOOP: we only accept matching labels, so no need to update */
+}
+
+static int
+mls_mount_check_stat(struct ucred *cred, struct mount *mp,
+ struct label *mntlabel)
+{
+ struct mac_mls *subj, *obj;
+
+ if (!mls_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(mntlabel);
+
+ if (!mls_dominate_effective(subj, obj))
+ return (EACCES);
+
+ return (0);
+}
+
+static void
+mls_mount_create(struct ucred *cred, struct mount *mp, struct label *mplabel)
+{
+ struct mac_mls *source, *dest;
+
+ source = SLOT(cred->cr_label);
+ dest = SLOT(mplabel);
+
+ mls_copy_effective(source, dest);
+}
+
+static void
+mls_netatalk_aarp_send(struct ifnet *ifp, struct label *ifplabel,
+ struct mbuf *m, struct label *mlabel)
+{
+ struct mac_mls *dest;
+
+ dest = SLOT(mlabel);
+
+ mls_set_effective(dest, MAC_MLS_TYPE_EQUAL, 0, NULL);
+}
+
+static void
+mls_netinet_arp_send(struct ifnet *ifp, struct label *ifplabel,
+ struct mbuf *m, struct label *mlabel)
+{
+ struct mac_mls *dest;
+
+ dest = SLOT(mlabel);
+
+ mls_set_effective(dest, MAC_MLS_TYPE_EQUAL, 0, NULL);
+}
+
+static void
+mls_netinet_firewall_reply(struct mbuf *mrecv, struct label *mrecvlabel,
+ struct mbuf *msend, struct label *msendlabel)
+{
+ struct mac_mls *source, *dest;
+
+ source = SLOT(mrecvlabel);
+ dest = SLOT(msendlabel);
+
+ mls_copy_effective(source, dest);
+}
+
+static void
+mls_netinet_firewall_send(struct mbuf *m, struct label *mlabel)
+{
+ struct mac_mls *dest;
+
+ dest = SLOT(mlabel);
+
+ /* XXX: where is the label for the firewall really comming from? */
+ mls_set_effective(dest, MAC_MLS_TYPE_EQUAL, 0, NULL);
+}
+
+static void
+mls_netinet_fragment(struct mbuf *m, struct label *mlabel, struct mbuf *frag,
+ struct label *fraglabel)
+{
+ struct mac_mls *source, *dest;
+
+ source = SLOT(mlabel);
+ dest = SLOT(fraglabel);
+
+ mls_copy_effective(source, dest);
+}
+
+static void
+mls_netinet_icmp_reply(struct mbuf *mrecv, struct label *mrecvlabel,
+ struct mbuf *msend, struct label *msendlabel)
+{
+ struct mac_mls *source, *dest;
+
+ source = SLOT(mrecvlabel);
+ dest = SLOT(msendlabel);
+
+ mls_copy_effective(source, dest);
+}
+
+static void
+mls_netinet_igmp_send(struct ifnet *ifp, struct label *ifplabel,
+ struct mbuf *m, struct label *mlabel)
+{
+ struct mac_mls *dest;
+
+ dest = SLOT(mlabel);
+
+ mls_set_effective(dest, MAC_MLS_TYPE_EQUAL, 0, NULL);
+}
+
+static void
+mls_netinet6_nd6_send(struct ifnet *ifp, struct label *ifplabel,
+ struct mbuf *m, struct label *mlabel)
+{
+ struct mac_mls *dest;
+
+ dest = SLOT(mlabel);
+
+ mls_set_effective(dest, MAC_MLS_TYPE_EQUAL, 0, NULL);
+}
+
+static int
+mls_pipe_check_ioctl(struct ucred *cred, struct pipepair *pp,
+ struct label *pplabel, unsigned long cmd, void /* caddr_t */ *data)
+{
+
+ if (!mls_enabled)
+ return (0);
+
+ /* XXX: This will be implemented soon... */
+
+ return (0);
+}
+
+static int
+mls_pipe_check_poll(struct ucred *cred, struct pipepair *pp,
+ struct label *pplabel)
+{
+ struct mac_mls *subj, *obj;
+
+ if (!mls_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(pplabel);
+
+ if (!mls_dominate_effective(subj, obj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+mls_pipe_check_read(struct ucred *cred, struct pipepair *pp,
+ struct label *pplabel)
+{
+ struct mac_mls *subj, *obj;
+
+ if (!mls_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(pplabel);
+
+ if (!mls_dominate_effective(subj, obj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+mls_pipe_check_relabel(struct ucred *cred, struct pipepair *pp,
+ struct label *pplabel, struct label *newlabel)
+{
+ struct mac_mls *subj, *obj, *new;
+ int error;
+
+ new = SLOT(newlabel);
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(pplabel);
+
+ /*
+ * If there is an MLS label update for a pipe, it must be a effective
+ * update.
+ */
+ error = mls_atmostflags(new, MAC_MLS_FLAG_EFFECTIVE);
+ if (error)
+ return (error);
+
+ /*
+ * To perform a relabel of a pipe (MLS label or not), MLS must
+ * authorize the relabel.
+ */
+ if (!mls_effective_in_range(obj, subj))
+ return (EPERM);
+
+ /*
+ * If the MLS label is to be changed, authorize as appropriate.
+ */
+ if (new->mm_flags & MAC_MLS_FLAG_EFFECTIVE) {
+ /*
+ * To change the MLS label on a pipe, the new pipe label must
+ * be in the subject range.
+ */
+ if (!mls_effective_in_range(new, subj))
+ return (EPERM);
+
+ /*
+ * To change the MLS label on a pipe to be EQUAL, the subject
+ * must have appropriate privilege.
+ */
+ if (mls_contains_equal(new)) {
+ error = mls_subject_privileged(subj);
+ if (error)
+ return (error);
+ }
+ }
+
+ return (0);
+}
+
+static int
+mls_pipe_check_stat(struct ucred *cred, struct pipepair *pp,
+ struct label *pplabel)
+{
+ struct mac_mls *subj, *obj;
+
+ if (!mls_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(pplabel);
+
+ if (!mls_dominate_effective(subj, obj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+mls_pipe_check_write(struct ucred *cred, struct pipepair *pp,
+ struct label *pplabel)
+{
+ struct mac_mls *subj, *obj;
+
+ if (!mls_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(pplabel);
+
+ if (!mls_dominate_effective(obj, subj))
+ return (EACCES);
+
+ return (0);
+}
+
+static void
+mls_pipe_create(struct ucred *cred, struct pipepair *pp,
+ struct label *pplabel)
+{
+ struct mac_mls *source, *dest;
+
+ source = SLOT(cred->cr_label);
+ dest = SLOT(pplabel);
+
+ mls_copy_effective(source, dest);
+}
+
+static void
+mls_pipe_relabel(struct ucred *cred, struct pipepair *pp,
+ struct label *pplabel, struct label *newlabel)
+{
+ struct mac_mls *source, *dest;
+
+ source = SLOT(newlabel);
+ dest = SLOT(pplabel);
+
+ mls_copy(source, dest);
+}
+
+static int
+mls_posixsem_check_openunlink(struct ucred *cred, struct ksem *ks,
+ struct label *kslabel)
+{
+ struct mac_mls *subj, *obj;
+
+ if (!mls_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(kslabel);
+
+ if (!mls_dominate_effective(obj, subj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+mls_posixsem_check_rdonly(struct ucred *active_cred, struct ucred *file_cred,
+ struct ksem *ks, struct label *kslabel)
+{
+ struct mac_mls *subj, *obj;
+
+ if (!mls_enabled)
+ return (0);
+
+ subj = SLOT(active_cred->cr_label);
+ obj = SLOT(kslabel);
+
+ if (!mls_dominate_effective(subj, obj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+mls_posixsem_check_write(struct ucred *active_cred, struct ucred *file_cred,
+ struct ksem *ks, struct label *kslabel)
+{
+ struct mac_mls *subj, *obj;
+
+ if (!mls_enabled)
+ return (0);
+
+ subj = SLOT(active_cred->cr_label);
+ obj = SLOT(kslabel);
+
+ if (!mls_dominate_effective(obj, subj))
+ return (EACCES);
+
+ return (0);
+}
+
+static void
+mls_posixsem_create(struct ucred *cred, struct ksem *ks,
+ struct label *kslabel)
+{
+ struct mac_mls *source, *dest;
+
+ source = SLOT(cred->cr_label);
+ dest = SLOT(kslabel);
+
+ mls_copy_effective(source, dest);
+}
+
+static int
+mls_proc_check_debug(struct ucred *cred, struct proc *p)
+{
+ struct mac_mls *subj, *obj;
+
+ if (!mls_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(p->p_ucred->cr_label);
+
+ /* XXX: range checks */
+ if (!mls_dominate_effective(subj, obj))
+ return (ESRCH);
+ if (!mls_dominate_effective(obj, subj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+mls_proc_check_sched(struct ucred *cred, struct proc *p)
+{
+ struct mac_mls *subj, *obj;
+
+ if (!mls_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(p->p_ucred->cr_label);
+
+ /* XXX: range checks */
+ if (!mls_dominate_effective(subj, obj))
+ return (ESRCH);
+ if (!mls_dominate_effective(obj, subj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+mls_proc_check_signal(struct ucred *cred, struct proc *p, int signum)
+{
+ struct mac_mls *subj, *obj;
+
+ if (!mls_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(p->p_ucred->cr_label);
+
+ /* XXX: range checks */
+ if (!mls_dominate_effective(subj, obj))
+ return (ESRCH);
+ if (!mls_dominate_effective(obj, subj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+mls_socket_check_deliver(struct socket *so, struct label *solabel,
+ struct mbuf *m, struct label *mlabel)
+{
+ struct mac_mls *p, *s;
+
+ if (!mls_enabled)
+ return (0);
+
+ p = SLOT(mlabel);
+ s = SLOT(solabel);
+
+ return (mls_equal_effective(p, s) ? 0 : EACCES);
+}
+
+static int
+mls_socket_check_relabel(struct ucred *cred, struct socket *so,
+ struct label *solabel, struct label *newlabel)
+{
+ struct mac_mls *subj, *obj, *new;
+ int error;
+
+ new = SLOT(newlabel);
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(solabel);
+
+ /*
+ * If there is an MLS label update for the socket, it may be an
+ * update of effective.
+ */
+ error = mls_atmostflags(new, MAC_MLS_FLAG_EFFECTIVE);
+ if (error)
+ return (error);
+
+ /*
+ * To relabel a socket, the old socket effective must be in the
+ * subject range.
+ */
+ if (!mls_effective_in_range(obj, subj))
+ return (EPERM);
+
+ /*
+ * If the MLS label is to be changed, authorize as appropriate.
+ */
+ if (new->mm_flags & MAC_MLS_FLAG_EFFECTIVE) {
+ /*
+ * To relabel a socket, the new socket effective must be in
+ * the subject range.
+ */
+ if (!mls_effective_in_range(new, subj))
+ return (EPERM);
+
+ /*
+ * To change the MLS label on the socket to contain EQUAL,
+ * the subject must have appropriate privilege.
+ */
+ if (mls_contains_equal(new)) {
+ error = mls_subject_privileged(subj);
+ if (error)
+ return (error);
+ }
+ }
+
+ return (0);
+}
+
+static int
+mls_socket_check_visible(struct ucred *cred, struct socket *so,
+ struct label *solabel)
+{
+ struct mac_mls *subj, *obj;
+
+ if (!mls_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(solabel);
+
+ if (!mls_dominate_effective(subj, obj))
+ return (ENOENT);
+
+ return (0);
+}
+
+static void
+mls_socket_create(struct ucred *cred, struct socket *so,
+ struct label *solabel)
+{
+ struct mac_mls *source, *dest;
+
+ source = SLOT(cred->cr_label);
+ dest = SLOT(solabel);
+
+ mls_copy_effective(source, dest);
+}
+
+static void
+mls_socket_create_mbuf(struct socket *so, struct label *solabel,
+ struct mbuf *m, struct label *mlabel)
+{
+ struct mac_mls *source, *dest;
+
+ source = SLOT(solabel);
+ dest = SLOT(mlabel);
+
+ mls_copy_effective(source, dest);
+}
+
+static void
+mls_socket_newconn(struct socket *oldso, struct label *oldsolabel,
+ struct socket *newso, struct label *newsolabel)
+{
+ struct mac_mls *source, *dest;
+
+ source = SLOT(oldsolabel);
+ dest = SLOT(newsolabel);
+
+ mls_copy_effective(source, dest);
+}
+
+static void
+mls_socket_relabel(struct ucred *cred, struct socket *so,
+ struct label *solabel, struct label *newlabel)
+{
+ struct mac_mls *source, *dest;
+
+ source = SLOT(newlabel);
+ dest = SLOT(solabel);
+
+ mls_copy(source, dest);
+}
+
+static void
+mls_socketpeer_set_from_mbuf(struct mbuf *m, struct label *mlabel,
+ struct socket *so, struct label *sopeerlabel)
+{
+ struct mac_mls *source, *dest;
+
+ source = SLOT(mlabel);
+ dest = SLOT(sopeerlabel);
+
+ mls_copy_effective(source, dest);
+}
+
+static void
+mls_socketpeer_set_from_socket(struct socket *oldso,
+ struct label *oldsolabel, struct socket *newso,
+ struct label *newsopeerlabel)
+{
+ struct mac_mls *source, *dest;
+
+ source = SLOT(oldsolabel);
+ dest = SLOT(newsopeerlabel);
+
+ mls_copy_effective(source, dest);
+}
+
+static void
+mls_syncache_create(struct label *label, struct inpcb *inp)
+{
+ struct mac_mls *source, *dest;
+
+ source = SLOT(inp->inp_label);
+ dest = SLOT(label);
+
+ mls_copy_effective(source, dest);
+}
+
+static void
+mls_syncache_create_mbuf(struct label *sc_label, struct mbuf *m,
+ struct label *mlabel)
+{
+ struct mac_mls *source, *dest;
+
+ source = SLOT(sc_label);
+ dest = SLOT(mlabel);
+
+ mls_copy_effective(source, dest);
+}
+
+static int
+mls_system_check_acct(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel)
+{
+ struct mac_mls *subj, *obj;
+
+ if (!mls_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(vplabel);
+
+ if (!mls_dominate_effective(obj, subj) ||
+ !mls_dominate_effective(subj, obj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+mls_system_check_auditctl(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel)
+{
+ struct mac_mls *subj, *obj;
+
+ if (!mls_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(vplabel);
+
+ if (!mls_dominate_effective(obj, subj) ||
+ !mls_dominate_effective(subj, obj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+mls_system_check_swapon(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel)
+{
+ struct mac_mls *subj, *obj;
+
+ if (!mls_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(vplabel);
+
+ if (!mls_dominate_effective(obj, subj) ||
+ !mls_dominate_effective(subj, obj))
+ return (EACCES);
+
+ return (0);
+}
+
+static void
+mls_sysvmsg_cleanup(struct label *msglabel)
+{
+
+ bzero(SLOT(msglabel), sizeof(struct mac_mls));
+}
+
+static void
+mls_sysvmsg_create(struct ucred *cred, struct msqid_kernel *msqkptr,
+ struct label *msqlabel, struct msg *msgptr, struct label *msglabel)
+{
+ struct mac_mls *source, *dest;
+
+ /* Ignore the msgq label. */
+ source = SLOT(cred->cr_label);
+ dest = SLOT(msglabel);
+
+ mls_copy_effective(source, dest);
+}
+
+static int
+mls_sysvmsq_check_msgrcv(struct ucred *cred, struct msg *msgptr,
+ struct label *msglabel)
+{
+ struct mac_mls *subj, *obj;
+
+ if (!mls_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(msglabel);
+
+ if (!mls_dominate_effective(subj, obj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+mls_sysvmsq_check_msgrmid(struct ucred *cred, struct msg *msgptr,
+ struct label *msglabel)
+{
+ struct mac_mls *subj, *obj;
+
+ if (!mls_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(msglabel);
+
+ if (!mls_dominate_effective(obj, subj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+mls_sysvmsq_check_msqget(struct ucred *cred, struct msqid_kernel *msqkptr,
+ struct label *msqklabel)
+{
+ struct mac_mls *subj, *obj;
+
+ if (!mls_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(msqklabel);
+
+ if (!mls_dominate_effective(subj, obj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+mls_sysvmsq_check_msqsnd(struct ucred *cred, struct msqid_kernel *msqkptr,
+ struct label *msqklabel)
+{
+ struct mac_mls *subj, *obj;
+
+ if (!mls_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(msqklabel);
+
+ if (!mls_dominate_effective(obj, subj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+mls_sysvmsq_check_msqrcv(struct ucred *cred, struct msqid_kernel *msqkptr,
+ struct label *msqklabel)
+{
+ struct mac_mls *subj, *obj;
+
+ if (!mls_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(msqklabel);
+
+ if (!mls_dominate_effective(subj, obj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+mls_sysvmsq_check_msqctl(struct ucred *cred, struct msqid_kernel *msqkptr,
+ struct label *msqklabel, int cmd)
+{
+ struct mac_mls *subj, *obj;
+
+ if (!mls_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(msqklabel);
+
+ switch(cmd) {
+ case IPC_RMID:
+ case IPC_SET:
+ if (!mls_dominate_effective(obj, subj))
+ return (EACCES);
+ break;
+
+ case IPC_STAT:
+ if (!mls_dominate_effective(subj, obj))
+ return (EACCES);
+ break;
+
+ default:
+ return (EACCES);
+ }
+
+ return (0);
+}
+
+static void
+mls_sysvmsq_cleanup(struct label *msqlabel)
+{
+
+ bzero(SLOT(msqlabel), sizeof(struct mac_mls));
+}
+
+static void
+mls_sysvmsq_create(struct ucred *cred, struct msqid_kernel *msqkptr,
+ struct label *msqlabel)
+{
+ struct mac_mls *source, *dest;
+
+ source = SLOT(cred->cr_label);
+ dest = SLOT(msqlabel);
+
+ mls_copy_effective(source, dest);
+}
+
+static int
+mls_sysvsem_check_semctl(struct ucred *cred, struct semid_kernel *semakptr,
+ struct label *semaklabel, int cmd)
+{
+ struct mac_mls *subj, *obj;
+
+ if (!mls_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(semaklabel);
+
+ switch(cmd) {
+ case IPC_RMID:
+ case IPC_SET:
+ case SETVAL:
+ case SETALL:
+ if (!mls_dominate_effective(obj, subj))
+ return (EACCES);
+ break;
+
+ case IPC_STAT:
+ case GETVAL:
+ case GETPID:
+ case GETNCNT:
+ case GETZCNT:
+ case GETALL:
+ if (!mls_dominate_effective(subj, obj))
+ return (EACCES);
+ break;
+
+ default:
+ return (EACCES);
+ }
+
+ return (0);
+}
+
+static int
+mls_sysvsem_check_semget(struct ucred *cred, struct semid_kernel *semakptr,
+ struct label *semaklabel)
+{
+ struct mac_mls *subj, *obj;
+
+ if (!mls_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(semaklabel);
+
+ if (!mls_dominate_effective(subj, obj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+mls_sysvsem_check_semop(struct ucred *cred, struct semid_kernel *semakptr,
+ struct label *semaklabel, size_t accesstype)
+{
+ struct mac_mls *subj, *obj;
+
+ if (!mls_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(semaklabel);
+
+ if( accesstype & SEM_R )
+ if (!mls_dominate_effective(subj, obj))
+ return (EACCES);
+
+ if( accesstype & SEM_A )
+ if (!mls_dominate_effective(obj, subj))
+ return (EACCES);
+
+ return (0);
+}
+
+static void
+mls_sysvsem_cleanup(struct label *semalabel)
+{
+
+ bzero(SLOT(semalabel), sizeof(struct mac_mls));
+}
+
+static void
+mls_sysvsem_create(struct ucred *cred, struct semid_kernel *semakptr,
+ struct label *semalabel)
+{
+ struct mac_mls *source, *dest;
+
+ source = SLOT(cred->cr_label);
+ dest = SLOT(semalabel);
+
+ mls_copy_effective(source, dest);
+}
+
+static int
+mls_sysvshm_check_shmat(struct ucred *cred, struct shmid_kernel *shmsegptr,
+ struct label *shmseglabel, int shmflg)
+{
+ struct mac_mls *subj, *obj;
+
+ if (!mls_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(shmseglabel);
+
+ if (!mls_dominate_effective(subj, obj))
+ return (EACCES);
+ if ((shmflg & SHM_RDONLY) == 0) {
+ if (!mls_dominate_effective(obj, subj))
+ return (EACCES);
+ }
+
+ return (0);
+}
+
+static int
+mls_sysvshm_check_shmctl(struct ucred *cred, struct shmid_kernel *shmsegptr,
+ struct label *shmseglabel, int cmd)
+{
+ struct mac_mls *subj, *obj;
+
+ if (!mls_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(shmseglabel);
+
+ switch(cmd) {
+ case IPC_RMID:
+ case IPC_SET:
+ if (!mls_dominate_effective(obj, subj))
+ return (EACCES);
+ break;
+
+ case IPC_STAT:
+ case SHM_STAT:
+ if (!mls_dominate_effective(subj, obj))
+ return (EACCES);
+ break;
+
+ default:
+ return (EACCES);
+ }
+
+ return (0);
+}
+
+static int
+mls_sysvshm_check_shmget(struct ucred *cred, struct shmid_kernel *shmsegptr,
+ struct label *shmseglabel, int shmflg)
+{
+ struct mac_mls *subj, *obj;
+
+ if (!mls_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(shmseglabel);
+
+ if (!mls_dominate_effective(obj, subj))
+ return (EACCES);
+
+ return (0);
+}
+
+static void
+mls_sysvshm_cleanup(struct label *shmlabel)
+{
+
+ bzero(SLOT(shmlabel), sizeof(struct mac_mls));
+}
+
+static void
+mls_sysvshm_create(struct ucred *cred, struct shmid_kernel *shmsegptr,
+ struct label *shmlabel)
+{
+ struct mac_mls *source, *dest;
+
+ source = SLOT(cred->cr_label);
+ dest = SLOT(shmlabel);
+
+ mls_copy_effective(source, dest);
+}
+
+static int
+mls_vnode_associate_extattr(struct mount *mp, struct label *mplabel,
+ struct vnode *vp, struct label *vplabel)
+{
+ struct mac_mls mm_temp, *source, *dest;
+ int buflen, error;
+
+ source = SLOT(mplabel);
+ dest = SLOT(vplabel);
+
+ buflen = sizeof(mm_temp);
+ bzero(&mm_temp, buflen);
+
+ error = vn_extattr_get(vp, IO_NODELOCKED, MAC_MLS_EXTATTR_NAMESPACE,
+ MAC_MLS_EXTATTR_NAME, &buflen, (char *) &mm_temp, curthread);
+ if (error == ENOATTR || error == EOPNOTSUPP) {
+ /* Fall back to the mntlabel. */
+ mls_copy_effective(source, dest);
+ return (0);
+ } else if (error)
+ return (error);
+
+ if (buflen != sizeof(mm_temp)) {
+ printf("mls_vnode_associate_extattr: bad size %d\n", buflen);
+ return (EPERM);
+ }
+ if (mls_valid(&mm_temp) != 0) {
+ printf("mls_vnode_associate_extattr: invalid\n");
+ return (EPERM);
+ }
+ if ((mm_temp.mm_flags & MAC_MLS_FLAGS_BOTH) !=
+ MAC_MLS_FLAG_EFFECTIVE) {
+ printf("mls_associated_vnode_extattr: not effective\n");
+ return (EPERM);
+ }
+
+ mls_copy_effective(&mm_temp, dest);
+ return (0);
+}
+
+static void
+mls_vnode_associate_singlelabel(struct mount *mp, struct label *mplabel,
+ struct vnode *vp, struct label *vplabel)
+{
+ struct mac_mls *source, *dest;
+
+ source = SLOT(mplabel);
+ dest = SLOT(vplabel);
+
+ mls_copy_effective(source, dest);
+}
+
+static int
+mls_vnode_check_chdir(struct ucred *cred, struct vnode *dvp,
+ struct label *dvplabel)
+{
+ struct mac_mls *subj, *obj;
+
+ if (!mls_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(dvplabel);
+
+ if (!mls_dominate_effective(subj, obj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+mls_vnode_check_chroot(struct ucred *cred, struct vnode *dvp,
+ struct label *dvplabel)
+{
+ struct mac_mls *subj, *obj;
+
+ if (!mls_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(dvplabel);
+
+ if (!mls_dominate_effective(subj, obj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+mls_vnode_check_create(struct ucred *cred, struct vnode *dvp,
+ struct label *dvplabel, struct componentname *cnp, struct vattr *vap)
+{
+ struct mac_mls *subj, *obj;
+
+ if (!mls_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(dvplabel);
+
+ if (!mls_dominate_effective(obj, subj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+mls_vnode_check_deleteacl(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, acl_type_t type)
+{
+ struct mac_mls *subj, *obj;
+
+ if (!mls_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(vplabel);
+
+ if (!mls_dominate_effective(obj, subj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+mls_vnode_check_deleteextattr(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, int attrnamespace, const char *name)
+{
+ struct mac_mls *subj, *obj;
+
+ if (!mls_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(vplabel);
+
+ if (!mls_dominate_effective(obj, subj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+mls_vnode_check_exec(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, struct image_params *imgp,
+ struct label *execlabel)
+{
+ struct mac_mls *subj, *obj, *exec;
+ int error;
+
+ if (execlabel != NULL) {
+ /*
+ * We currently don't permit labels to be changed at
+ * exec-time as part of MLS, so disallow non-NULL MLS label
+ * elements in the execlabel.
+ */
+ exec = SLOT(execlabel);
+ error = mls_atmostflags(exec, 0);
+ if (error)
+ return (error);
+ }
+
+ if (!mls_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(vplabel);
+
+ if (!mls_dominate_effective(subj, obj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+mls_vnode_check_getacl(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, acl_type_t type)
+{
+ struct mac_mls *subj, *obj;
+
+ if (!mls_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(vplabel);
+
+ if (!mls_dominate_effective(subj, obj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+mls_vnode_check_getextattr(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, int attrnamespace, const char *name,
+ struct uio *uio)
+{
+ struct mac_mls *subj, *obj;
+
+ if (!mls_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(vplabel);
+
+ if (!mls_dominate_effective(subj, obj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+mls_vnode_check_link(struct ucred *cred, struct vnode *dvp,
+ struct label *dvplabel, struct vnode *vp, struct label *vplabel,
+ struct componentname *cnp)
+{
+ struct mac_mls *subj, *obj;
+
+ if (!mls_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(dvplabel);
+
+ if (!mls_dominate_effective(obj, subj))
+ return (EACCES);
+
+ obj = SLOT(vplabel);
+ if (!mls_dominate_effective(obj, subj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+mls_vnode_check_listextattr(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, int attrnamespace)
+{
+
+ struct mac_mls *subj, *obj;
+
+ if (!mls_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(vplabel);
+
+ if (!mls_dominate_effective(subj, obj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+mls_vnode_check_lookup(struct ucred *cred, struct vnode *dvp,
+ struct label *dvplabel, struct componentname *cnp)
+{
+ struct mac_mls *subj, *obj;
+
+ if (!mls_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(dvplabel);
+
+ if (!mls_dominate_effective(subj, obj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+mls_vnode_check_mmap(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, int prot, int flags)
+{
+ struct mac_mls *subj, *obj;
+
+ /*
+ * Rely on the use of open()-time protections to handle
+ * non-revocation cases.
+ */
+ if (!mls_enabled || !revocation_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(vplabel);
+
+ if (prot & (VM_PROT_READ | VM_PROT_EXECUTE)) {
+ if (!mls_dominate_effective(subj, obj))
+ return (EACCES);
+ }
+ if (((prot & VM_PROT_WRITE) != 0) && ((flags & MAP_SHARED) != 0)) {
+ if (!mls_dominate_effective(obj, subj))
+ return (EACCES);
+ }
+
+ return (0);
+}
+
+static int
+mls_vnode_check_open(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, accmode_t accmode)
+{
+ struct mac_mls *subj, *obj;
+
+ if (!mls_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(vplabel);
+
+ /* XXX privilege override for admin? */
+ if (accmode & (VREAD | VEXEC | VSTAT)) {
+ if (!mls_dominate_effective(subj, obj))
+ return (EACCES);
+ }
+ if (accmode & (VWRITE | VAPPEND | VADMIN)) {
+ if (!mls_dominate_effective(obj, subj))
+ return (EACCES);
+ }
+
+ return (0);
+}
+
+static int
+mls_vnode_check_poll(struct ucred *active_cred, struct ucred *file_cred,
+ struct vnode *vp, struct label *vplabel)
+{
+ struct mac_mls *subj, *obj;
+
+ if (!mls_enabled || !revocation_enabled)
+ return (0);
+
+ subj = SLOT(active_cred->cr_label);
+ obj = SLOT(vplabel);
+
+ if (!mls_dominate_effective(subj, obj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+mls_vnode_check_read(struct ucred *active_cred, struct ucred *file_cred,
+ struct vnode *vp, struct label *vplabel)
+{
+ struct mac_mls *subj, *obj;
+
+ if (!mls_enabled || !revocation_enabled)
+ return (0);
+
+ subj = SLOT(active_cred->cr_label);
+ obj = SLOT(vplabel);
+
+ if (!mls_dominate_effective(subj, obj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+mls_vnode_check_readdir(struct ucred *cred, struct vnode *dvp,
+ struct label *dvplabel)
+{
+ struct mac_mls *subj, *obj;
+
+ if (!mls_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(dvplabel);
+
+ if (!mls_dominate_effective(subj, obj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+mls_vnode_check_readlink(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel)
+{
+ struct mac_mls *subj, *obj;
+
+ if (!mls_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(vplabel);
+
+ if (!mls_dominate_effective(subj, obj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+mls_vnode_check_relabel(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, struct label *newlabel)
+{
+ struct mac_mls *old, *new, *subj;
+ int error;
+
+ old = SLOT(vplabel);
+ new = SLOT(newlabel);
+ subj = SLOT(cred->cr_label);
+
+ /*
+ * If there is an MLS label update for the vnode, it must be a
+ * effective label.
+ */
+ error = mls_atmostflags(new, MAC_MLS_FLAG_EFFECTIVE);
+ if (error)
+ return (error);
+
+ /*
+ * To perform a relabel of the vnode (MLS label or not), MLS must
+ * authorize the relabel.
+ */
+ if (!mls_effective_in_range(old, subj))
+ return (EPERM);
+
+ /*
+ * If the MLS label is to be changed, authorize as appropriate.
+ */
+ if (new->mm_flags & MAC_MLS_FLAG_EFFECTIVE) {
+ /*
+ * To change the MLS label on a vnode, the new vnode label
+ * must be in the subject range.
+ */
+ if (!mls_effective_in_range(new, subj))
+ return (EPERM);
+
+ /*
+ * To change the MLS label on the vnode to be EQUAL, the
+ * subject must have appropriate privilege.
+ */
+ if (mls_contains_equal(new)) {
+ error = mls_subject_privileged(subj);
+ if (error)
+ return (error);
+ }
+ }
+
+ return (0);
+}
+
+static int
+mls_vnode_check_rename_from(struct ucred *cred, struct vnode *dvp,
+ struct label *dvplabel, struct vnode *vp, struct label *vplabel,
+ struct componentname *cnp)
+{
+ struct mac_mls *subj, *obj;
+
+ if (!mls_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(dvplabel);
+
+ if (!mls_dominate_effective(obj, subj))
+ return (EACCES);
+
+ obj = SLOT(vplabel);
+
+ if (!mls_dominate_effective(obj, subj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+mls_vnode_check_rename_to(struct ucred *cred, struct vnode *dvp,
+ struct label *dvplabel, struct vnode *vp, struct label *vplabel,
+ int samedir, struct componentname *cnp)
+{
+ struct mac_mls *subj, *obj;
+
+ if (!mls_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(dvplabel);
+
+ if (!mls_dominate_effective(obj, subj))
+ return (EACCES);
+
+ if (vp != NULL) {
+ obj = SLOT(vplabel);
+
+ if (!mls_dominate_effective(obj, subj))
+ return (EACCES);
+ }
+
+ return (0);
+}
+
+static int
+mls_vnode_check_revoke(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel)
+{
+ struct mac_mls *subj, *obj;
+
+ if (!mls_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(vplabel);
+
+ if (!mls_dominate_effective(obj, subj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+mls_vnode_check_setacl(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, acl_type_t type, struct acl *acl)
+{
+ struct mac_mls *subj, *obj;
+
+ if (!mls_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(vplabel);
+
+ if (!mls_dominate_effective(obj, subj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+mls_vnode_check_setextattr(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, int attrnamespace, const char *name,
+ struct uio *uio)
+{
+ struct mac_mls *subj, *obj;
+
+ if (!mls_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(vplabel);
+
+ if (!mls_dominate_effective(obj, subj))
+ return (EACCES);
+
+ /* XXX: protect the MAC EA in a special way? */
+
+ return (0);
+}
+
+static int
+mls_vnode_check_setflags(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, u_long flags)
+{
+ struct mac_mls *subj, *obj;
+
+ if (!mls_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(vplabel);
+
+ if (!mls_dominate_effective(obj, subj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+mls_vnode_check_setmode(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, mode_t mode)
+{
+ struct mac_mls *subj, *obj;
+
+ if (!mls_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(vplabel);
+
+ if (!mls_dominate_effective(obj, subj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+mls_vnode_check_setowner(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, uid_t uid, gid_t gid)
+{
+ struct mac_mls *subj, *obj;
+
+ if (!mls_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(vplabel);
+
+ if (!mls_dominate_effective(obj, subj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+mls_vnode_check_setutimes(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, struct timespec atime, struct timespec mtime)
+{
+ struct mac_mls *subj, *obj;
+
+ if (!mls_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(vplabel);
+
+ if (!mls_dominate_effective(obj, subj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+mls_vnode_check_stat(struct ucred *active_cred, struct ucred *file_cred,
+ struct vnode *vp, struct label *vplabel)
+{
+ struct mac_mls *subj, *obj;
+
+ if (!mls_enabled)
+ return (0);
+
+ subj = SLOT(active_cred->cr_label);
+ obj = SLOT(vplabel);
+
+ if (!mls_dominate_effective(subj, obj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+mls_vnode_check_unlink(struct ucred *cred, struct vnode *dvp,
+ struct label *dvplabel, struct vnode *vp, struct label *vplabel,
+ struct componentname *cnp)
+{
+ struct mac_mls *subj, *obj;
+
+ if (!mls_enabled)
+ return (0);
+
+ subj = SLOT(cred->cr_label);
+ obj = SLOT(dvplabel);
+
+ if (!mls_dominate_effective(obj, subj))
+ return (EACCES);
+
+ obj = SLOT(vplabel);
+
+ if (!mls_dominate_effective(obj, subj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+mls_vnode_check_write(struct ucred *active_cred, struct ucred *file_cred,
+ struct vnode *vp, struct label *vplabel)
+{
+ struct mac_mls *subj, *obj;
+
+ if (!mls_enabled || !revocation_enabled)
+ return (0);
+
+ subj = SLOT(active_cred->cr_label);
+ obj = SLOT(vplabel);
+
+ if (!mls_dominate_effective(obj, subj))
+ return (EACCES);
+
+ return (0);
+}
+
+static int
+mls_vnode_create_extattr(struct ucred *cred, struct mount *mp,
+ struct label *mplabel, struct vnode *dvp, struct label *dvplabel,
+ struct vnode *vp, struct label *vplabel, struct componentname *cnp)
+{
+ struct mac_mls *source, *dest, mm_temp;
+ size_t buflen;
+ int error;
+
+ buflen = sizeof(mm_temp);
+ bzero(&mm_temp, buflen);
+
+ source = SLOT(cred->cr_label);
+ dest = SLOT(vplabel);
+ mls_copy_effective(source, &mm_temp);
+
+ error = vn_extattr_set(vp, IO_NODELOCKED, MAC_MLS_EXTATTR_NAMESPACE,
+ MAC_MLS_EXTATTR_NAME, buflen, (char *) &mm_temp, curthread);
+ if (error == 0)
+ mls_copy_effective(source, dest);
+ return (error);
+}
+
+static void
+mls_vnode_relabel(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, struct label *label)
+{
+ struct mac_mls *source, *dest;
+
+ source = SLOT(label);
+ dest = SLOT(vplabel);
+
+ mls_copy(source, dest);
+}
+
+static int
+mls_vnode_setlabel_extattr(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, struct label *intlabel)
+{
+ struct mac_mls *source, mm_temp;
+ size_t buflen;
+ int error;
+
+ buflen = sizeof(mm_temp);
+ bzero(&mm_temp, buflen);
+
+ source = SLOT(intlabel);
+ if ((source->mm_flags & MAC_MLS_FLAG_EFFECTIVE) == 0)
+ return (0);
+
+ mls_copy_effective(source, &mm_temp);
+
+ error = vn_extattr_set(vp, IO_NODELOCKED, MAC_MLS_EXTATTR_NAMESPACE,
+ MAC_MLS_EXTATTR_NAME, buflen, (char *) &mm_temp, curthread);
+ return (error);
+}
+
+static struct mac_policy_ops mls_ops =
+{
+ .mpo_init = mls_init,
+
+ .mpo_bpfdesc_check_receive = mls_bpfdesc_check_receive,
+ .mpo_bpfdesc_create = mls_bpfdesc_create,
+ .mpo_bpfdesc_create_mbuf = mls_bpfdesc_create_mbuf,
+ .mpo_bpfdesc_destroy_label = mls_destroy_label,
+ .mpo_bpfdesc_init_label = mls_init_label,
+
+ .mpo_cred_associate_nfsd = mls_cred_associate_nfsd,
+ .mpo_cred_check_relabel = mls_cred_check_relabel,
+ .mpo_cred_check_visible = mls_cred_check_visible,
+ .mpo_cred_copy_label = mls_copy_label,
+ .mpo_cred_create_init = mls_cred_create_init,
+ .mpo_cred_create_swapper = mls_cred_create_swapper,
+ .mpo_cred_destroy_label = mls_destroy_label,
+ .mpo_cred_externalize_label = mls_externalize_label,
+ .mpo_cred_init_label = mls_init_label,
+ .mpo_cred_internalize_label = mls_internalize_label,
+ .mpo_cred_relabel = mls_cred_relabel,
+
+ .mpo_devfs_create_device = mls_devfs_create_device,
+ .mpo_devfs_create_directory = mls_devfs_create_directory,
+ .mpo_devfs_create_symlink = mls_devfs_create_symlink,
+ .mpo_devfs_destroy_label = mls_destroy_label,
+ .mpo_devfs_init_label = mls_init_label,
+ .mpo_devfs_update = mls_devfs_update,
+ .mpo_devfs_vnode_associate = mls_devfs_vnode_associate,
+
+ .mpo_ifnet_check_relabel = mls_ifnet_check_relabel,
+ .mpo_ifnet_check_transmit = mls_ifnet_check_transmit,
+ .mpo_ifnet_copy_label = mls_copy_label,
+ .mpo_ifnet_create = mls_ifnet_create,
+ .mpo_ifnet_create_mbuf = mls_ifnet_create_mbuf,
+ .mpo_ifnet_destroy_label = mls_destroy_label,
+ .mpo_ifnet_externalize_label = mls_externalize_label,
+ .mpo_ifnet_init_label = mls_init_label,
+ .mpo_ifnet_internalize_label = mls_internalize_label,
+ .mpo_ifnet_relabel = mls_ifnet_relabel,
+
+ .mpo_inpcb_check_deliver = mls_inpcb_check_deliver,
+ .mpo_inpcb_check_visible = mls_inpcb_check_visible,
+ .mpo_inpcb_create = mls_inpcb_create,
+ .mpo_inpcb_create_mbuf = mls_inpcb_create_mbuf,
+ .mpo_inpcb_destroy_label = mls_destroy_label,
+ .mpo_inpcb_init_label = mls_init_label_waitcheck,
+ .mpo_inpcb_sosetlabel = mls_inpcb_sosetlabel,
+
+ .mpo_ip6q_create = mls_ip6q_create,
+ .mpo_ip6q_destroy_label = mls_destroy_label,
+ .mpo_ip6q_init_label = mls_init_label_waitcheck,
+ .mpo_ip6q_match = mls_ip6q_match,
+ .mpo_ip6q_reassemble = mls_ip6q_reassemble,
+ .mpo_ip6q_update = mls_ip6q_update,
+
+ .mpo_ipq_create = mls_ipq_create,
+ .mpo_ipq_destroy_label = mls_destroy_label,
+ .mpo_ipq_init_label = mls_init_label_waitcheck,
+ .mpo_ipq_match = mls_ipq_match,
+ .mpo_ipq_reassemble = mls_ipq_reassemble,
+ .mpo_ipq_update = mls_ipq_update,
+
+ .mpo_mbuf_copy_label = mls_copy_label,
+ .mpo_mbuf_destroy_label = mls_destroy_label,
+ .mpo_mbuf_init_label = mls_init_label_waitcheck,
+
+ .mpo_mount_check_stat = mls_mount_check_stat,
+ .mpo_mount_create = mls_mount_create,
+ .mpo_mount_destroy_label = mls_destroy_label,
+ .mpo_mount_init_label = mls_init_label,
+
+ .mpo_netatalk_aarp_send = mls_netatalk_aarp_send,
+
+ .mpo_netinet_arp_send = mls_netinet_arp_send,
+ .mpo_netinet_firewall_reply = mls_netinet_firewall_reply,
+ .mpo_netinet_firewall_send = mls_netinet_firewall_send,
+ .mpo_netinet_fragment = mls_netinet_fragment,
+ .mpo_netinet_icmp_reply = mls_netinet_icmp_reply,
+ .mpo_netinet_igmp_send = mls_netinet_igmp_send,
+
+ .mpo_netinet6_nd6_send = mls_netinet6_nd6_send,
+
+ .mpo_pipe_check_ioctl = mls_pipe_check_ioctl,
+ .mpo_pipe_check_poll = mls_pipe_check_poll,
+ .mpo_pipe_check_read = mls_pipe_check_read,
+ .mpo_pipe_check_relabel = mls_pipe_check_relabel,
+ .mpo_pipe_check_stat = mls_pipe_check_stat,
+ .mpo_pipe_check_write = mls_pipe_check_write,
+ .mpo_pipe_copy_label = mls_copy_label,
+ .mpo_pipe_create = mls_pipe_create,
+ .mpo_pipe_destroy_label = mls_destroy_label,
+ .mpo_pipe_externalize_label = mls_externalize_label,
+ .mpo_pipe_init_label = mls_init_label,
+ .mpo_pipe_internalize_label = mls_internalize_label,
+ .mpo_pipe_relabel = mls_pipe_relabel,
+
+ .mpo_posixsem_check_getvalue = mls_posixsem_check_rdonly,
+ .mpo_posixsem_check_open = mls_posixsem_check_openunlink,
+ .mpo_posixsem_check_post = mls_posixsem_check_write,
+ .mpo_posixsem_check_stat = mls_posixsem_check_rdonly,
+ .mpo_posixsem_check_unlink = mls_posixsem_check_openunlink,
+ .mpo_posixsem_check_wait = mls_posixsem_check_write,
+ .mpo_posixsem_create = mls_posixsem_create,
+ .mpo_posixsem_destroy_label = mls_destroy_label,
+ .mpo_posixsem_init_label = mls_init_label,
+
+ .mpo_proc_check_debug = mls_proc_check_debug,
+ .mpo_proc_check_sched = mls_proc_check_sched,
+ .mpo_proc_check_signal = mls_proc_check_signal,
+
+ .mpo_socket_check_deliver = mls_socket_check_deliver,
+ .mpo_socket_check_relabel = mls_socket_check_relabel,
+ .mpo_socket_check_visible = mls_socket_check_visible,
+ .mpo_socket_copy_label = mls_copy_label,
+ .mpo_socket_create = mls_socket_create,
+ .mpo_socket_create_mbuf = mls_socket_create_mbuf,
+ .mpo_socket_destroy_label = mls_destroy_label,
+ .mpo_socket_externalize_label = mls_externalize_label,
+ .mpo_socket_init_label = mls_init_label_waitcheck,
+ .mpo_socket_internalize_label = mls_internalize_label,
+ .mpo_socket_newconn = mls_socket_newconn,
+ .mpo_socket_relabel = mls_socket_relabel,
+
+ .mpo_socketpeer_destroy_label = mls_destroy_label,
+ .mpo_socketpeer_externalize_label = mls_externalize_label,
+ .mpo_socketpeer_init_label = mls_init_label_waitcheck,
+ .mpo_socketpeer_set_from_mbuf = mls_socketpeer_set_from_mbuf,
+ .mpo_socketpeer_set_from_socket = mls_socketpeer_set_from_socket,
+
+ .mpo_syncache_create = mls_syncache_create,
+ .mpo_syncache_create_mbuf = mls_syncache_create_mbuf,
+ .mpo_syncache_destroy_label = mls_destroy_label,
+ .mpo_syncache_init_label = mls_init_label_waitcheck,
+
+ .mpo_sysvmsg_cleanup = mls_sysvmsg_cleanup,
+ .mpo_sysvmsg_create = mls_sysvmsg_create,
+ .mpo_sysvmsg_destroy_label = mls_destroy_label,
+ .mpo_sysvmsg_init_label = mls_init_label,
+
+ .mpo_sysvmsq_check_msgrcv = mls_sysvmsq_check_msgrcv,
+ .mpo_sysvmsq_check_msgrmid = mls_sysvmsq_check_msgrmid,
+ .mpo_sysvmsq_check_msqget = mls_sysvmsq_check_msqget,
+ .mpo_sysvmsq_check_msqsnd = mls_sysvmsq_check_msqsnd,
+ .mpo_sysvmsq_check_msqrcv = mls_sysvmsq_check_msqrcv,
+ .mpo_sysvmsq_check_msqctl = mls_sysvmsq_check_msqctl,
+ .mpo_sysvmsq_cleanup = mls_sysvmsq_cleanup,
+ .mpo_sysvmsq_destroy_label = mls_destroy_label,
+ .mpo_sysvmsq_init_label = mls_init_label,
+ .mpo_sysvmsq_create = mls_sysvmsq_create,
+
+ .mpo_sysvsem_check_semctl = mls_sysvsem_check_semctl,
+ .mpo_sysvsem_check_semget = mls_sysvsem_check_semget,
+ .mpo_sysvsem_check_semop = mls_sysvsem_check_semop,
+ .mpo_sysvsem_cleanup = mls_sysvsem_cleanup,
+ .mpo_sysvsem_create = mls_sysvsem_create,
+ .mpo_sysvsem_destroy_label = mls_destroy_label,
+ .mpo_sysvsem_init_label = mls_init_label,
+
+ .mpo_sysvshm_check_shmat = mls_sysvshm_check_shmat,
+ .mpo_sysvshm_check_shmctl = mls_sysvshm_check_shmctl,
+ .mpo_sysvshm_check_shmget = mls_sysvshm_check_shmget,
+ .mpo_sysvshm_cleanup = mls_sysvshm_cleanup,
+ .mpo_sysvshm_create = mls_sysvshm_create,
+ .mpo_sysvshm_destroy_label = mls_destroy_label,
+ .mpo_sysvshm_init_label = mls_init_label,
+
+
+ .mpo_system_check_acct = mls_system_check_acct,
+ .mpo_system_check_auditctl = mls_system_check_auditctl,
+ .mpo_system_check_swapon = mls_system_check_swapon,
+
+ .mpo_vnode_associate_extattr = mls_vnode_associate_extattr,
+ .mpo_vnode_associate_singlelabel = mls_vnode_associate_singlelabel,
+ .mpo_vnode_check_access = mls_vnode_check_open,
+ .mpo_vnode_check_chdir = mls_vnode_check_chdir,
+ .mpo_vnode_check_chroot = mls_vnode_check_chroot,
+ .mpo_vnode_check_create = mls_vnode_check_create,
+ .mpo_vnode_check_deleteacl = mls_vnode_check_deleteacl,
+ .mpo_vnode_check_deleteextattr = mls_vnode_check_deleteextattr,
+ .mpo_vnode_check_exec = mls_vnode_check_exec,
+ .mpo_vnode_check_getacl = mls_vnode_check_getacl,
+ .mpo_vnode_check_getextattr = mls_vnode_check_getextattr,
+ .mpo_vnode_check_link = mls_vnode_check_link,
+ .mpo_vnode_check_listextattr = mls_vnode_check_listextattr,
+ .mpo_vnode_check_lookup = mls_vnode_check_lookup,
+ .mpo_vnode_check_mmap = mls_vnode_check_mmap,
+ .mpo_vnode_check_open = mls_vnode_check_open,
+ .mpo_vnode_check_poll = mls_vnode_check_poll,
+ .mpo_vnode_check_read = mls_vnode_check_read,
+ .mpo_vnode_check_readdir = mls_vnode_check_readdir,
+ .mpo_vnode_check_readlink = mls_vnode_check_readlink,
+ .mpo_vnode_check_relabel = mls_vnode_check_relabel,
+ .mpo_vnode_check_rename_from = mls_vnode_check_rename_from,
+ .mpo_vnode_check_rename_to = mls_vnode_check_rename_to,
+ .mpo_vnode_check_revoke = mls_vnode_check_revoke,
+ .mpo_vnode_check_setacl = mls_vnode_check_setacl,
+ .mpo_vnode_check_setextattr = mls_vnode_check_setextattr,
+ .mpo_vnode_check_setflags = mls_vnode_check_setflags,
+ .mpo_vnode_check_setmode = mls_vnode_check_setmode,
+ .mpo_vnode_check_setowner = mls_vnode_check_setowner,
+ .mpo_vnode_check_setutimes = mls_vnode_check_setutimes,
+ .mpo_vnode_check_stat = mls_vnode_check_stat,
+ .mpo_vnode_check_unlink = mls_vnode_check_unlink,
+ .mpo_vnode_check_write = mls_vnode_check_write,
+ .mpo_vnode_copy_label = mls_copy_label,
+ .mpo_vnode_create_extattr = mls_vnode_create_extattr,
+ .mpo_vnode_destroy_label = mls_destroy_label,
+ .mpo_vnode_externalize_label = mls_externalize_label,
+ .mpo_vnode_init_label = mls_init_label,
+ .mpo_vnode_internalize_label = mls_internalize_label,
+ .mpo_vnode_relabel = mls_vnode_relabel,
+ .mpo_vnode_setlabel_extattr = mls_vnode_setlabel_extattr,
+};
+
+#define MLS_OBJECTS (MPC_OBJECT_CRED | \
+ /* MPC_OBJECT_PROC | */ \
+ MPC_OBJECT_VNODE | \
+ MPC_OBJECT_INPCB | \
+ MPC_OBJECT_SOCKET | \
+ MPC_OBJECT_DEVFS | \
+ MPC_OBJECT_MBUF | \
+ MPC_OBJECT_IPQ | \
+ MPC_OBJECT_IFNET | \
+ MPC_OBJECT_BPFDESC | \
+ MPC_OBJECT_PIPE | \
+ MPC_OBJECT_MOUNT | \
+ MPC_OBJECT_POSIXSEM | \
+ /* MPC_OBJECT_POSIXSHM | */ \
+ MPC_OBJECT_SYSVMSG | \
+ MPC_OBJECT_SYSVMSQ | \
+ MPC_OBJECT_SYSVSEM | \
+ MPC_OBJECT_SYSVSHM | \
+ MPC_OBJECT_SYNCACHE)
+
+MAC_POLICY_SET(&mls_ops, mac_mls, "TrustedBSD MAC/MLS",
+ MPC_LOADTIME_FLAG_NOTLATE, &mls_slot, MLS_OBJECTS);
diff --git a/sys/security/mac_mls/mac_mls.h b/sys/security/mac_mls/mac_mls.h
new file mode 100644
index 0000000..7bed921
--- /dev/null
+++ b/sys/security/mac_mls/mac_mls.h
@@ -0,0 +1,102 @@
+/*-
+ * Copyright (c) 1999-2002 Robert N. M. Watson
+ * Copyright (c) 2001-2004 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * This software was developed by Robert Watson for the TrustedBSD Project.
+ *
+ * This software was developed for the FreeBSD Project in part by Network
+ * Associates Laboratories, the Security Research Division of Network
+ * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"),
+ * as part of the DARPA CHATS research program.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+/*
+ * Definitions for the TrustedBSD MLS confidentiality policy module.
+ */
+#ifndef _SYS_SECURITY_MAC_MLS_H
+#define _SYS_SECURITY_MAC_MLS_H
+
+#define MAC_MLS_EXTATTR_NAMESPACE EXTATTR_NAMESPACE_SYSTEM
+#define MAC_MLS_EXTATTR_NAME "mac_mls"
+
+#define MAC_MLS_LABEL_NAME "mls"
+
+#define MAC_MLS_FLAG_EFFECTIVE 0x00000001 /* mm_effective initialized */
+#define MAC_MLS_FLAG_RANGE 0x00000002 /* mm_range* initialized */
+#define MAC_MLS_FLAGS_BOTH (MAC_MLS_FLAG_EFFECTIVE | MAC_MLS_FLAG_RANGE)
+
+#define MAC_MLS_TYPE_UNDEF 0 /* Undefined */
+#define MAC_MLS_TYPE_LEVEL 1 /* Hierarchal level with mm_level. */
+#define MAC_MLS_TYPE_LOW 2 /* Dominated by any
+ * MAC_MLS_TYPE_LABEL. */
+#define MAC_MLS_TYPE_HIGH 3 /* Dominates any
+ * MAC_MLS_TYPE_LABEL. */
+#define MAC_MLS_TYPE_EQUAL 4 /* Equivilent to any
+ * MAC_MLS_TYPE_LABEL. */
+
+/*
+ * Structures and constants associated with a Multi-Level Security policy.
+ * mac_mls represents an MLS label, with mm_type determining its properties,
+ * and mm_level represents the hierarchal sensitivity level if valid for the
+ * current mm_type. If compartments are used, the same semantics apply as
+ * long as the suject is in every compartment the object is in. LOW, EQUAL
+ * and HIGH cannot be in compartments.
+ */
+
+/*
+ * MLS compartments bit set size (in bits).
+ */
+#define MAC_MLS_MAX_COMPARTMENTS 256
+
+struct mac_mls_element {
+ u_short mme_type;
+ u_short mme_level;
+ u_char mme_compartments[MAC_MLS_MAX_COMPARTMENTS >> 3];
+};
+
+/*
+ * MLS labels consist of two components: an effective label, and a label
+ * range. Depending on the context, one or both may be used; the mb_flags
+ * field permits the provider to indicate what fields are intended for
+ * use.
+ */
+struct mac_mls {
+ int mm_flags;
+ struct mac_mls_element mm_effective;
+ struct mac_mls_element mm_rangelow, mm_rangehigh;
+};
+
+/*
+ * MLS compartments bit test/set macros.
+ * The range is 1 to MAC_MLS_MAX_COMPARTMENTS.
+ */
+#define MAC_MLS_BIT_TEST(b, w) \
+ ((w)[(((b) - 1) >> 3)] & (1 << (((b) - 1) & 7)))
+#define MAC_MLS_BIT_SET(b, w) \
+ ((w)[(((b) - 1) >> 3)] |= (1 << (((b) - 1) & 7)))
+#define MAC_MLS_BIT_SET_EMPTY(set) mls_bit_set_empty(set)
+
+#endif /* !_SYS_SECURITY_MAC_MLS_H */
diff --git a/sys/security/mac_none/mac_none.c b/sys/security/mac_none/mac_none.c
new file mode 100644
index 0000000..d57c309
--- /dev/null
+++ b/sys/security/mac_none/mac_none.c
@@ -0,0 +1,56 @@
+/*-
+ * Copyright (c) 1999-2002, 2007 Robert N. M. Watson
+ * Copyright (c) 2001-2003 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * This software was developed by Robert Watson for the TrustedBSD Project.
+ *
+ * This software was developed for the FreeBSD Project in part by Network
+ * Associates Laboratories, the Security Research Division of Network
+ * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"),
+ * as part of the DARPA CHATS research program.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Developed by the TrustedBSD Project.
+ *
+ * Sample policy implementing no entry points; for performance measurement
+ * purposes only. If you're looking for a stub policy to base new policies
+ * on, try mac_stub.
+ */
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+
+#include <security/mac/mac_policy.h>
+
+static struct mac_policy_ops none_ops =
+{
+};
+
+MAC_POLICY_SET(&none_ops, mac_none, "TrustedBSD MAC/None",
+ MPC_LOADTIME_FLAG_UNLOADOK, NULL, 0);
diff --git a/sys/security/mac_partition/mac_partition.c b/sys/security/mac_partition/mac_partition.c
new file mode 100644
index 0000000..7eca1f9
--- /dev/null
+++ b/sys/security/mac_partition/mac_partition.c
@@ -0,0 +1,319 @@
+/*-
+ * Copyright (c) 1999-2002, 2007-2008 Robert N. M. Watson
+ * Copyright (c) 2001-2002 Networks Associates Technology, Inc.
+ * Copyright (c) 2006 SPARTA, Inc.
+ * Copyright (c) 2008 Apple Inc.
+ * All rights reserved.
+ *
+ * This software was developed by Robert Watson for the TrustedBSD Project.
+ *
+ * This software was developed for the FreeBSD Project in part by Network
+ * Associates Laboratories, the Security Research Division of Network
+ * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"),
+ * as part of the DARPA CHATS research program.
+ *
+ * This software was enhanced by SPARTA ISSO under SPAWAR contract
+ * N66001-04-C-6019 ("SEFOS").
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Developed by the TrustedBSD Project.
+ *
+ * Experiment with a partition-like model.
+ */
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/priv.h>
+#include <sys/proc.h>
+#include <sys/sbuf.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/systm.h>
+#include <sys/sysctl.h>
+
+#include <net/route.h>
+#include <netinet/in.h>
+#include <netinet/in_pcb.h>
+
+#include <security/mac/mac_policy.h>
+#include <security/mac_partition/mac_partition.h>
+
+SYSCTL_DECL(_security_mac);
+
+SYSCTL_NODE(_security_mac, OID_AUTO, partition, CTLFLAG_RW, 0,
+ "TrustedBSD mac_partition policy controls");
+
+static int partition_enabled = 1;
+SYSCTL_INT(_security_mac_partition, OID_AUTO, enabled, CTLFLAG_RW,
+ &partition_enabled, 0, "Enforce partition policy");
+
+static int partition_slot;
+#define SLOT(l) mac_label_get((l), partition_slot)
+#define SLOT_SET(l, v) mac_label_set((l), partition_slot, (v))
+
+static int
+partition_check(struct label *subject, struct label *object)
+{
+
+ if (partition_enabled == 0)
+ return (0);
+
+ if (subject == NULL)
+ return (0);
+
+ if (SLOT(subject) == 0)
+ return (0);
+
+ /*
+ * If the object label hasn't been allocated, then it's effectively
+ * not in a partition, and we know the subject is as it has a label
+ * and it's not 0, so reject.
+ */
+ if (object == NULL)
+ return (EPERM);
+
+ if (SLOT(subject) == SLOT(object))
+ return (0);
+
+ return (EPERM);
+}
+
+/*
+ * Object-specific entry points are sorted alphabetically by object type name
+ * and then by operation.
+ */
+static int
+partition_cred_check_relabel(struct ucred *cred, struct label *newlabel)
+{
+ int error;
+
+ error = 0;
+
+ /*
+ * Treat "0" as a no-op request because it reflects an unset
+ * partition label. If we ever want to support switching back to an
+ * unpartitioned state for a process, we'll need to differentiate the
+ * "not in a partition" and "no partition defined during internalize"
+ * conditions.
+ */
+ if (SLOT(newlabel) != 0) {
+ /*
+ * Require BSD privilege in order to change the partition.
+ * Originally we also required that the process not be in a
+ * partition in the first place, but this didn't interact
+ * well with sendmail.
+ */
+ error = priv_check_cred(cred, PRIV_MAC_PARTITION, 0);
+ }
+
+ return (error);
+}
+
+static int
+partition_cred_check_visible(struct ucred *cr1, struct ucred *cr2)
+{
+ int error;
+
+ error = partition_check(cr1->cr_label, cr2->cr_label);
+
+ return (error == 0 ? 0 : ESRCH);
+}
+
+static void
+partition_cred_copy_label(struct label *src, struct label *dest)
+{
+
+ if (src != NULL && dest != NULL)
+ SLOT_SET(dest, SLOT(src));
+ else if (dest != NULL)
+ SLOT_SET(dest, 0);
+}
+
+static void
+partition_cred_create_init(struct ucred *cred)
+{
+
+ SLOT_SET(cred->cr_label, 0);
+}
+
+static void
+partition_cred_create_swapper(struct ucred *cred)
+{
+
+ SLOT_SET(cred->cr_label, 0);
+}
+
+static void
+partition_cred_destroy_label(struct label *label)
+{
+
+ SLOT_SET(label, 0);
+}
+
+static int
+partition_cred_externalize_label(struct label *label, char *element_name,
+ struct sbuf *sb, int *claimed)
+{
+
+ if (strcmp(MAC_PARTITION_LABEL_NAME, element_name) != 0)
+ return (0);
+
+ (*claimed)++;
+
+ if (label != NULL) {
+ if (sbuf_printf(sb, "%jd", (intmax_t)SLOT(label)) == -1)
+ return (EINVAL);
+ } else {
+ if (sbuf_printf(sb, "0") == -1)
+ return (EINVAL);
+ }
+ return (0);
+}
+
+static void
+partition_cred_init_label(struct label *label)
+{
+
+ SLOT_SET(label, 0);
+}
+
+static int
+partition_cred_internalize_label(struct label *label, char *element_name,
+ char *element_data, int *claimed)
+{
+
+ if (strcmp(MAC_PARTITION_LABEL_NAME, element_name) != 0)
+ return (0);
+
+ (*claimed)++;
+ SLOT_SET(label, strtol(element_data, NULL, 10));
+ return (0);
+}
+
+static void
+partition_cred_relabel(struct ucred *cred, struct label *newlabel)
+{
+
+ if (newlabel != NULL && SLOT(newlabel) != 0)
+ SLOT_SET(cred->cr_label, SLOT(newlabel));
+}
+
+static int
+partition_inpcb_check_visible(struct ucred *cred, struct inpcb *inp,
+ struct label *inplabel)
+{
+ int error;
+
+ error = partition_check(cred->cr_label, inp->inp_cred->cr_label);
+
+ return (error ? ENOENT : 0);
+}
+
+static int
+partition_proc_check_debug(struct ucred *cred, struct proc *p)
+{
+ int error;
+
+ error = partition_check(cred->cr_label, p->p_ucred->cr_label);
+
+ return (error ? ESRCH : 0);
+}
+
+static int
+partition_proc_check_sched(struct ucred *cred, struct proc *p)
+{
+ int error;
+
+ error = partition_check(cred->cr_label, p->p_ucred->cr_label);
+
+ return (error ? ESRCH : 0);
+}
+
+static int
+partition_proc_check_signal(struct ucred *cred, struct proc *p,
+ int signum)
+{
+ int error;
+
+ error = partition_check(cred->cr_label, p->p_ucred->cr_label);
+
+ return (error ? ESRCH : 0);
+}
+
+static int
+partition_socket_check_visible(struct ucred *cred, struct socket *so,
+ struct label *solabel)
+{
+ int error;
+
+ error = partition_check(cred->cr_label, so->so_cred->cr_label);
+
+ return (error ? ENOENT : 0);
+}
+
+static int
+partition_vnode_check_exec(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, struct image_params *imgp,
+ struct label *execlabel)
+{
+
+ if (execlabel != NULL) {
+ /*
+ * We currently don't permit labels to be changed at
+ * exec-time as part of the partition model, so disallow
+ * non-NULL partition label changes in execlabel.
+ */
+ if (SLOT(execlabel) != 0)
+ return (EINVAL);
+ }
+
+ return (0);
+}
+
+static struct mac_policy_ops partition_ops =
+{
+ .mpo_cred_check_relabel = partition_cred_check_relabel,
+ .mpo_cred_check_visible = partition_cred_check_visible,
+ .mpo_cred_copy_label = partition_cred_copy_label,
+ .mpo_cred_create_init = partition_cred_create_init,
+ .mpo_cred_create_swapper = partition_cred_create_swapper,
+ .mpo_cred_destroy_label = partition_cred_destroy_label,
+ .mpo_cred_externalize_label = partition_cred_externalize_label,
+ .mpo_cred_init_label = partition_cred_init_label,
+ .mpo_cred_internalize_label = partition_cred_internalize_label,
+ .mpo_cred_relabel = partition_cred_relabel,
+ .mpo_inpcb_check_visible = partition_inpcb_check_visible,
+ .mpo_proc_check_debug = partition_proc_check_debug,
+ .mpo_proc_check_sched = partition_proc_check_sched,
+ .mpo_proc_check_signal = partition_proc_check_signal,
+ .mpo_socket_check_visible = partition_socket_check_visible,
+ .mpo_vnode_check_exec = partition_vnode_check_exec,
+};
+
+MAC_POLICY_SET(&partition_ops, mac_partition, "TrustedBSD MAC/Partition",
+ MPC_LOADTIME_FLAG_UNLOADOK, &partition_slot, MPC_OBJECT_CRED);
diff --git a/sys/security/mac_partition/mac_partition.h b/sys/security/mac_partition/mac_partition.h
new file mode 100644
index 0000000..f5675e2
--- /dev/null
+++ b/sys/security/mac_partition/mac_partition.h
@@ -0,0 +1,46 @@
+/*-
+ * Copyright (c) 1999-2002 Robert N. M. Watson
+ * Copyright (c) 2001-2002 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * This software was developed by Robert Watson for the TrustedBSD Project.
+ *
+ * This software was developed for the FreeBSD Project in part by Network
+ * Associates Laboratories, the Security Research Division of Network
+ * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"),
+ * as part of the DARPA CHATS research program.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Definitions for the TrustedBSD partition policy module.
+ */
+
+#ifndef _SYS_SECURITY_MAC_PARTITION_H
+#define _SYS_SECURITY_MAC_PARTITION_H
+
+#define MAC_PARTITION_LABEL_NAME "partition"
+
+#endif /* !_SYS_SECURITY_MAC_PARTITION_H */
diff --git a/sys/security/mac_portacl/mac_portacl.c b/sys/security/mac_portacl/mac_portacl.c
new file mode 100644
index 0000000..eb388cc
--- /dev/null
+++ b/sys/security/mac_portacl/mac_portacl.c
@@ -0,0 +1,493 @@
+/*-
+ * Copyright (c) 2003-2004 Networks Associates Technology, Inc.
+ * Copyright (c) 2006 SPARTA, Inc.
+ * All rights reserved.
+ *
+ * This software was developed for the FreeBSD Project by Network
+ * Associates Laboratories, the Security Research Division of Network
+ * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"),
+ * as part of the DARPA CHATS research program.
+ *
+ * This software was enhanced by SPARTA ISSO under SPAWAR contract
+ * N66001-04-C-6019 ("SEFOS").
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Developed by the TrustedBSD Project.
+ *
+ * Administratively limit access to local UDP/TCP ports for binding purposes.
+ * Intended to be combined with net.inet.ip.portrange.reservedhigh to allow
+ * specific uids and gids to bind specific ports for specific purposes,
+ * while not opening the door to any user replacing an "official" service
+ * while you're restarting it. This only affects ports explicitly bound by
+ * the user process (either for listen/outgoing socket for TCP, or send/
+ * receive for UDP). This module will not limit ports bound implicitly for
+ * out-going connections where the process hasn't explicitly selected a port:
+ * these are automatically selected by the IP stack.
+ *
+ * To use this module, security.mac.enforce_socket must be enabled, and you
+ * will probably want to twiddle the net.inet sysctl listed above. Then use
+ * sysctl(8) to modify the rules string:
+ *
+ * # sysctl security.mac.portacl.rules="uid:425:tcp:80,uid:425:tcp:79"
+ *
+ * This ruleset, for example, permits uid 425 to bind TCP ports 80 (http) and
+ * 79 (finger). User names and group names can't be used directly because
+ * the kernel only knows about uids and gids.
+ */
+
+#include <sys/param.h>
+#include <sys/domain.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/priv.h>
+#include <sys/proc.h>
+#include <sys/protosw.h>
+#include <sys/queue.h>
+#include <sys/systm.h>
+#include <sys/sbuf.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/sysctl.h>
+
+#include <netinet/in.h>
+#include <netinet/in_pcb.h>
+
+#include <security/mac/mac_policy.h>
+
+SYSCTL_DECL(_security_mac);
+
+SYSCTL_NODE(_security_mac, OID_AUTO, portacl, CTLFLAG_RW, 0,
+ "TrustedBSD mac_portacl policy controls");
+
+static int portacl_enabled = 1;
+SYSCTL_INT(_security_mac_portacl, OID_AUTO, enabled, CTLFLAG_RW,
+ &portacl_enabled, 0, "Enforce portacl policy");
+TUNABLE_INT("security.mac.portacl.enabled", &portacl_enabled);
+
+static int portacl_suser_exempt = 1;
+SYSCTL_INT(_security_mac_portacl, OID_AUTO, suser_exempt, CTLFLAG_RW,
+ &portacl_suser_exempt, 0, "Privilege permits binding of any port");
+TUNABLE_INT("security.mac.portacl.suser_exempt",
+ &portacl_suser_exempt);
+
+static int portacl_autoport_exempt = 1;
+SYSCTL_INT(_security_mac_portacl, OID_AUTO, autoport_exempt, CTLFLAG_RW,
+ &portacl_autoport_exempt, 0, "Allow automatic allocation through "
+ "binding port 0 if not IP_PORTRANGELOW");
+TUNABLE_INT("security.mac.portacl.autoport_exempt",
+ &portacl_autoport_exempt);
+
+static int portacl_port_high = 1023;
+SYSCTL_INT(_security_mac_portacl, OID_AUTO, port_high, CTLFLAG_RW,
+ &portacl_port_high, 0, "Highest port to enforce for");
+TUNABLE_INT("security.mac.portacl.port_high", &portacl_port_high);
+
+MALLOC_DEFINE(M_PORTACL, "portacl_rule", "Rules for mac_portacl");
+
+#define MAC_RULE_STRING_LEN 1024
+
+#define RULE_GID 1
+#define RULE_UID 2
+#define RULE_PROTO_TCP 1
+#define RULE_PROTO_UDP 2
+struct rule {
+ id_t r_id;
+ int r_idtype;
+ u_int16_t r_port;
+ int r_protocol;
+
+ TAILQ_ENTRY(rule) r_entries;
+};
+
+#define GID_STRING "gid"
+#define TCP_STRING "tcp"
+#define UID_STRING "uid"
+#define UDP_STRING "udp"
+
+/*
+ * Text format for the rule string is that a rule consists of a
+ * comma-seperated list of elements. Each element is in the form
+ * idtype:id:protocol:portnumber, and constitutes granting of permission
+ * for the specified binding.
+ */
+
+static struct mtx rule_mtx;
+static TAILQ_HEAD(rulehead, rule) rule_head;
+static char rule_string[MAC_RULE_STRING_LEN];
+
+static void
+toast_rules(struct rulehead *head)
+{
+ struct rule *rule;
+
+ while ((rule = TAILQ_FIRST(head)) != NULL) {
+ TAILQ_REMOVE(head, rule, r_entries);
+ free(rule, M_PORTACL);
+ }
+}
+
+/*
+ * Note that there is an inherent race condition in the unload of modules
+ * and access via sysctl.
+ */
+static void
+destroy(struct mac_policy_conf *mpc)
+{
+
+ mtx_destroy(&rule_mtx);
+ toast_rules(&rule_head);
+}
+
+static void
+init(struct mac_policy_conf *mpc)
+{
+
+ mtx_init(&rule_mtx, "rule_mtx", NULL, MTX_DEF);
+ TAILQ_INIT(&rule_head);
+}
+
+/*
+ * Note: parsing routines are destructive on the passed string.
+ */
+static int
+parse_rule_element(char *element, struct rule **rule)
+{
+ char *idtype, *id, *protocol, *portnumber, *p;
+ struct rule *new;
+ int error;
+
+ error = 0;
+ new = malloc(sizeof(*new), M_PORTACL, M_ZERO | M_WAITOK);
+
+ idtype = strsep(&element, ":");
+ if (idtype == NULL) {
+ error = EINVAL;
+ goto out;
+ }
+ id = strsep(&element, ":");
+ if (id == NULL) {
+ error = EINVAL;
+ goto out;
+ }
+ new->r_id = strtol(id, &p, 10);
+ if (*p != '\0') {
+ error = EINVAL;
+ goto out;
+ }
+ if (strcmp(idtype, UID_STRING) == 0)
+ new->r_idtype = RULE_UID;
+ else if (strcmp(idtype, GID_STRING) == 0)
+ new->r_idtype = RULE_GID;
+ else {
+ error = EINVAL;
+ goto out;
+ }
+ protocol = strsep(&element, ":");
+ if (protocol == NULL) {
+ error = EINVAL;
+ goto out;
+ }
+ if (strcmp(protocol, TCP_STRING) == 0)
+ new->r_protocol = RULE_PROTO_TCP;
+ else if (strcmp(protocol, UDP_STRING) == 0)
+ new->r_protocol = RULE_PROTO_UDP;
+ else {
+ error = EINVAL;
+ goto out;
+ }
+ portnumber = element;
+ if (portnumber == NULL) {
+ error = EINVAL;
+ goto out;
+ }
+ new->r_port = strtol(portnumber, &p, 10);
+ if (*p != '\0') {
+ error = EINVAL;
+ goto out;
+ }
+
+out:
+ if (error != 0) {
+ free(new, M_PORTACL);
+ *rule = NULL;
+ } else
+ *rule = new;
+ return (error);
+}
+
+static int
+parse_rules(char *string, struct rulehead *head)
+{
+ struct rule *new;
+ char *element;
+ int error;
+
+ error = 0;
+ while ((element = strsep(&string, ",")) != NULL) {
+ if (strlen(element) == 0)
+ continue;
+ error = parse_rule_element(element, &new);
+ if (error)
+ goto out;
+ TAILQ_INSERT_TAIL(head, new, r_entries);
+ }
+out:
+ if (error != 0)
+ toast_rules(head);
+ return (error);
+}
+
+/*
+ * rule_printf() and rules_to_string() are unused currently because they rely
+ * on sbufs with auto-extension, which may sleep while holding a mutex.
+ * Instead, the non-canonical user-generated rule string is returned to the
+ * user when the rules are queried, which is faster anyway.
+ */
+#if 0
+static void
+rule_printf(struct sbuf *sb, struct rule *rule)
+{
+ const char *idtype, *protocol;
+
+ switch(rule->r_idtype) {
+ case RULE_GID:
+ idtype = GID_STRING;
+ break;
+ case RULE_UID:
+ idtype = UID_STRING;
+ break;
+ default:
+ panic("rule_printf: unknown idtype (%d)\n", rule->r_idtype);
+ }
+
+ switch (rule->r_protocol) {
+ case RULE_PROTO_TCP:
+ protocol = TCP_STRING;
+ break;
+ case RULE_PROTO_UDP:
+ protocol = UDP_STRING;
+ break;
+ default:
+ panic("rule_printf: unknown protocol (%d)\n",
+ rule->r_protocol);
+ }
+ sbuf_printf(sb, "%s:%jd:%s:%d", idtype, (intmax_t)rule->r_id,
+ protocol, rule->r_port);
+}
+
+static char *
+rules_to_string(void)
+{
+ struct rule *rule;
+ struct sbuf *sb;
+ int needcomma;
+ char *temp;
+
+ sb = sbuf_new_auto();
+ needcomma = 0;
+ mtx_lock(&rule_mtx);
+ for (rule = TAILQ_FIRST(&rule_head); rule != NULL;
+ rule = TAILQ_NEXT(rule, r_entries)) {
+ if (!needcomma)
+ needcomma = 1;
+ else
+ sbuf_printf(sb, ",");
+ rule_printf(sb, rule);
+ }
+ mtx_unlock(&rule_mtx);
+ sbuf_finish(sb);
+ temp = strdup(sbuf_data(sb), M_PORTACL);
+ sbuf_delete(sb);
+ return (temp);
+}
+#endif
+
+/*
+ * Note: due to races, there is not a single serializable order
+ * between parallel calls to the sysctl.
+ */
+static int
+sysctl_rules(SYSCTL_HANDLER_ARGS)
+{
+ char *string, *copy_string, *new_string;
+ struct rulehead head, save_head;
+ int error;
+
+ new_string = NULL;
+ if (req->newptr == NULL) {
+ new_string = malloc(MAC_RULE_STRING_LEN, M_PORTACL,
+ M_WAITOK | M_ZERO);
+ strcpy(new_string, rule_string);
+ string = new_string;
+ } else
+ string = rule_string;
+
+ error = sysctl_handle_string(oidp, string, MAC_RULE_STRING_LEN, req);
+ if (error)
+ goto out;
+
+ if (req->newptr != NULL) {
+ copy_string = strdup(string, M_PORTACL);
+ TAILQ_INIT(&head);
+ error = parse_rules(copy_string, &head);
+ free(copy_string, M_PORTACL);
+ if (error)
+ goto out;
+
+ TAILQ_INIT(&save_head);
+ mtx_lock(&rule_mtx);
+ TAILQ_CONCAT(&save_head, &rule_head, r_entries);
+ TAILQ_CONCAT(&rule_head, &head, r_entries);
+ strcpy(rule_string, string);
+ mtx_unlock(&rule_mtx);
+ toast_rules(&save_head);
+ }
+out:
+ if (new_string != NULL)
+ free(new_string, M_PORTACL);
+ return (error);
+}
+
+SYSCTL_PROC(_security_mac_portacl, OID_AUTO, rules,
+ CTLTYPE_STRING|CTLFLAG_RW, 0, 0, sysctl_rules, "A", "Rules");
+
+static int
+rules_check(struct ucred *cred, int family, int type, u_int16_t port)
+{
+ struct rule *rule;
+ int error;
+
+#if 0
+ printf("Check requested for euid %d, family %d, type %d, port %d\n",
+ cred->cr_uid, family, type, port);
+#endif
+
+ if (port > portacl_port_high)
+ return (0);
+
+ error = EPERM;
+ mtx_lock(&rule_mtx);
+ for (rule = TAILQ_FIRST(&rule_head);
+ rule != NULL;
+ rule = TAILQ_NEXT(rule, r_entries)) {
+ if (type == SOCK_DGRAM && rule->r_protocol != RULE_PROTO_UDP)
+ continue;
+ if (type == SOCK_STREAM && rule->r_protocol != RULE_PROTO_TCP)
+ continue;
+ if (port != rule->r_port)
+ continue;
+ if (rule->r_idtype == RULE_UID) {
+ if (cred->cr_uid == rule->r_id) {
+ error = 0;
+ break;
+ }
+ } else if (rule->r_idtype == RULE_GID) {
+ if (cred->cr_gid == rule->r_id) {
+ error = 0;
+ break;
+ } else if (groupmember(rule->r_id, cred)) {
+ error = 0;
+ break;
+ }
+ } else
+ panic("rules_check: unknown rule type %d",
+ rule->r_idtype);
+ }
+ mtx_unlock(&rule_mtx);
+
+ if (error != 0 && portacl_suser_exempt != 0)
+ error = priv_check_cred(cred, PRIV_NETINET_RESERVEDPORT, 0);
+
+ return (error);
+}
+
+/*
+ * Note, this only limits the ability to explicitly bind a port, it
+ * doesn't limit implicitly bound ports for outgoing connections where
+ * the source port is left up to the IP stack to determine automatically.
+ */
+static int
+socket_check_bind(struct ucred *cred, struct socket *so,
+ struct label *solabel, struct sockaddr *sa)
+{
+ struct sockaddr_in *sin;
+ struct inpcb *inp;
+ int family, type;
+ u_int16_t port;
+
+ /* Only run if we are enabled. */
+ if (portacl_enabled == 0)
+ return (0);
+
+ /* Only interested in IPv4 and IPv6 sockets. */
+ if (so->so_proto->pr_domain->dom_family != PF_INET &&
+ so->so_proto->pr_domain->dom_family != PF_INET6)
+ return (0);
+
+ /* Currently, we don't attempt to deal with SOCK_RAW, etc. */
+ if (so->so_type != SOCK_DGRAM &&
+ so->so_type != SOCK_STREAM)
+ return (0);
+
+ /* Reject addresses we don't understand; fail closed. */
+ if (sa->sa_family != AF_INET && sa->sa_family != AF_INET6)
+ return (EINVAL);
+
+ family = so->so_proto->pr_domain->dom_family;
+ type = so->so_type;
+ sin = (struct sockaddr_in *) sa;
+ port = ntohs(sin->sin_port);
+
+ /*
+ * Sockets are frequently bound with a specific IP address but a port
+ * number of '0' to request automatic port allocation. This is often
+ * desirable as long as IP_PORTRANGELOW isn't set, which might permit
+ * automatic allocation of a "privileged" port. The autoport exempt
+ * flag exempts port 0 allocation from rule checking as long as a low
+ * port isn't required.
+ */
+ if (portacl_autoport_exempt && port == 0) {
+ inp = sotoinpcb(so);
+ if ((inp->inp_flags & INP_LOWPORT) == 0)
+ return (0);
+ }
+
+ return (rules_check(cred, family, type, port));
+}
+
+static struct mac_policy_ops portacl_ops =
+{
+ .mpo_destroy = destroy,
+ .mpo_init = init,
+ .mpo_socket_check_bind = socket_check_bind,
+};
+
+MAC_POLICY_SET(&portacl_ops, mac_portacl, "TrustedBSD MAC/portacl",
+ MPC_LOADTIME_FLAG_UNLOADOK, NULL, 0);
diff --git a/sys/security/mac_seeotheruids/mac_seeotheruids.c b/sys/security/mac_seeotheruids/mac_seeotheruids.c
new file mode 100644
index 0000000..ddbdaec
--- /dev/null
+++ b/sys/security/mac_seeotheruids/mac_seeotheruids.c
@@ -0,0 +1,189 @@
+/*-
+ * Copyright (c) 1999-2002, 2007 Robert N. M. Watson
+ * Copyright (c) 2001-2002 Networks Associates Technology, Inc.
+ * Copyright (c) 2006 SPARTA, Inc.
+ * All rights reserved.
+ *
+ * This software was developed by Robert Watson for the TrustedBSD Project.
+ *
+ * This software was developed for the FreeBSD Project in part by Network
+ * Associates Laboratories, the Security Research Division of Network
+ * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"),
+ * as part of the DARPA CHATS research program.
+ *
+ * This software was enhanced by SPARTA ISSO under SPAWAR contract
+ * N66001-04-C-6019 ("SEFOS").
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Developed by the TrustedBSD Project.
+ *
+ * Prevent processes owned by a particular uid from seeing various transient
+ * kernel objects associated with other uids.
+ */
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/priv.h>
+#include <sys/proc.h>
+#include <sys/systm.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/sysctl.h>
+
+#include <net/route.h>
+#include <netinet/in.h>
+#include <netinet/in_pcb.h>
+
+#include <security/mac/mac_policy.h>
+
+SYSCTL_DECL(_security_mac);
+
+SYSCTL_NODE(_security_mac, OID_AUTO, seeotheruids, CTLFLAG_RW, 0,
+ "TrustedBSD mac_seeotheruids policy controls");
+
+static int seeotheruids_enabled = 1;
+SYSCTL_INT(_security_mac_seeotheruids, OID_AUTO, enabled, CTLFLAG_RW,
+ &seeotheruids_enabled, 0, "Enforce seeotheruids policy");
+
+/*
+ * Exception: allow credentials to be aware of other credentials with the
+ * same primary gid.
+ */
+static int primarygroup_enabled = 0;
+SYSCTL_INT(_security_mac_seeotheruids, OID_AUTO, primarygroup_enabled,
+ CTLFLAG_RW, &primarygroup_enabled, 0, "Make an exception for credentials "
+ "with the same real primary group id");
+
+/*
+ * Exception: allow the root user to be aware of other credentials by virtue
+ * of privilege.
+ */
+static int suser_privileged = 1;
+SYSCTL_INT(_security_mac_seeotheruids, OID_AUTO, suser_privileged,
+ CTLFLAG_RW, &suser_privileged, 0, "Make an exception for superuser");
+
+/*
+ * Exception: allow processes with a specific gid to be exempt from the
+ * policy. One sysctl enables this functionality; the other sets the
+ * exempt gid.
+ */
+static int specificgid_enabled = 0;
+SYSCTL_INT(_security_mac_seeotheruids, OID_AUTO, specificgid_enabled,
+ CTLFLAG_RW, &specificgid_enabled, 0, "Make an exception for credentials "
+ "with a specific gid as their real primary group id or group set");
+
+static gid_t specificgid = 0;
+SYSCTL_INT(_security_mac_seeotheruids, OID_AUTO, specificgid, CTLFLAG_RW,
+ &specificgid, 0, "Specific gid to be exempt from seeotheruids policy");
+
+static int
+seeotheruids_check(struct ucred *cr1, struct ucred *cr2)
+{
+
+ if (!seeotheruids_enabled)
+ return (0);
+
+ if (primarygroup_enabled) {
+ if (cr1->cr_rgid == cr2->cr_rgid)
+ return (0);
+ }
+
+ if (specificgid_enabled) {
+ if (cr1->cr_rgid == specificgid ||
+ groupmember(specificgid, cr1))
+ return (0);
+ }
+
+ if (cr1->cr_ruid == cr2->cr_ruid)
+ return (0);
+
+ if (suser_privileged) {
+ if (priv_check_cred(cr1, PRIV_SEEOTHERUIDS, 0) == 0)
+ return (0);
+ }
+
+ return (ESRCH);
+}
+
+static int
+seeotheruids_proc_check_debug(struct ucred *cred, struct proc *p)
+{
+
+ return (seeotheruids_check(cred, p->p_ucred));
+}
+
+static int
+seeotheruids_proc_check_sched(struct ucred *cred, struct proc *p)
+{
+
+ return (seeotheruids_check(cred, p->p_ucred));
+}
+
+static int
+seeotheruids_proc_check_signal(struct ucred *cred, struct proc *p,
+ int signum)
+{
+
+ return (seeotheruids_check(cred, p->p_ucred));
+}
+
+static int
+seeotheruids_cred_check_visible(struct ucred *cr1, struct ucred *cr2)
+{
+
+ return (seeotheruids_check(cr1, cr2));
+}
+
+static int
+seeotheruids_inpcb_check_visible(struct ucred *cred, struct inpcb *inp,
+ struct label *inplabel)
+{
+
+ return (seeotheruids_check(cred, inp->inp_cred));
+}
+
+static int
+seeotheruids_socket_check_visible(struct ucred *cred, struct socket *so,
+ struct label *solabel)
+{
+
+ return (seeotheruids_check(cred, so->so_cred));
+}
+
+static struct mac_policy_ops seeotheruids_ops =
+{
+ .mpo_proc_check_debug = seeotheruids_proc_check_debug,
+ .mpo_proc_check_sched = seeotheruids_proc_check_sched,
+ .mpo_proc_check_signal = seeotheruids_proc_check_signal,
+ .mpo_cred_check_visible = seeotheruids_cred_check_visible,
+ .mpo_inpcb_check_visible = seeotheruids_inpcb_check_visible,
+ .mpo_socket_check_visible = seeotheruids_socket_check_visible,
+};
+
+MAC_POLICY_SET(&seeotheruids_ops, mac_seeotheruids,
+ "TrustedBSD MAC/seeotheruids", MPC_LOADTIME_FLAG_UNLOADOK, NULL, 0);
diff --git a/sys/security/mac_stub/mac_stub.c b/sys/security/mac_stub/mac_stub.c
new file mode 100644
index 0000000..02cb541
--- /dev/null
+++ b/sys/security/mac_stub/mac_stub.c
@@ -0,0 +1,1824 @@
+/*-
+ * Copyright (c) 1999-2002, 2007-2008 Robert N. M. Watson
+ * Copyright (c) 2001-2005 McAfee, Inc.
+ * Copyright (c) 2005-2006 SPARTA, Inc.
+ * Copyright (c) 2008 Apple Inc.
+ * All rights reserved.
+ *
+ * This software was developed by Robert Watson for the TrustedBSD Project.
+ *
+ * This software was developed for the FreeBSD Project in part by McAfee
+ * Research, the Security Research Division of McAfee, Inc. under
+ * DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA
+ * CHATS research program.
+ *
+ * This software was enhanced by SPARTA ISSO under SPAWAR contract
+ * N66001-04-C-6019 ("SEFOS").
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Developed by the TrustedBSD Project.
+ *
+ * Stub module that implements a NOOP for most (if not all) MAC Framework
+ * policy entry points.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/acl.h>
+#include <sys/conf.h>
+#include <sys/extattr.h>
+#include <sys/kernel.h>
+#include <sys/ksem.h>
+#include <sys/mount.h>
+#include <sys/proc.h>
+#include <sys/systm.h>
+#include <sys/sysproto.h>
+#include <sys/sysent.h>
+#include <sys/vnode.h>
+#include <sys/file.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/pipe.h>
+#include <sys/sx.h>
+#include <sys/sysctl.h>
+#include <sys/msg.h>
+#include <sys/sem.h>
+#include <sys/shm.h>
+
+#include <fs/devfs/devfs.h>
+
+#include <net/bpfdesc.h>
+#include <net/if.h>
+#include <net/if_types.h>
+#include <net/if_var.h>
+
+#include <netinet/in.h>
+#include <netinet/in_pcb.h>
+#include <netinet/ip_var.h>
+
+#include <vm/vm.h>
+
+#include <security/mac/mac_policy.h>
+
+SYSCTL_DECL(_security_mac);
+
+SYSCTL_NODE(_security_mac, OID_AUTO, stub, CTLFLAG_RW, 0,
+ "TrustedBSD mac_stub policy controls");
+
+static int stub_enabled = 1;
+SYSCTL_INT(_security_mac_stub, OID_AUTO, enabled, CTLFLAG_RW,
+ &stub_enabled, 0, "Enforce mac_stub policy");
+
+/*
+ * Policy module operations.
+ */
+static void
+stub_destroy(struct mac_policy_conf *conf)
+{
+
+}
+
+static void
+stub_init(struct mac_policy_conf *conf)
+{
+
+}
+
+static int
+stub_syscall(struct thread *td, int call, void *arg)
+{
+
+ return (0);
+}
+
+/*
+ * Label operations.
+ */
+static void
+stub_init_label(struct label *label)
+{
+
+}
+
+static int
+stub_init_label_waitcheck(struct label *label, int flag)
+{
+
+ return (0);
+}
+
+static void
+stub_destroy_label(struct label *label)
+{
+
+}
+
+static void
+stub_copy_label(struct label *src, struct label *dest)
+{
+
+}
+
+static int
+stub_externalize_label(struct label *label, char *element_name,
+ struct sbuf *sb, int *claimed)
+{
+
+ return (0);
+}
+
+static int
+stub_internalize_label(struct label *label, char *element_name,
+ char *element_data, int *claimed)
+{
+
+ return (0);
+}
+
+/*
+ * Object-specific entry point imeplementations are sorted alphabetically by
+ * object type name and then by operation.
+ */
+static int
+stub_bpfdesc_check_receive(struct bpf_d *d, struct label *dlabel,
+ struct ifnet *ifp, struct label *ifplabel)
+{
+
+ return (0);
+}
+
+static void
+stub_bpfdesc_create(struct ucred *cred, struct bpf_d *d,
+ struct label *dlabel)
+{
+
+}
+
+static void
+stub_bpfdesc_create_mbuf(struct bpf_d *d, struct label *dlabel,
+ struct mbuf *m, struct label *mlabel)
+{
+
+}
+
+static void
+stub_cred_associate_nfsd(struct ucred *cred)
+{
+
+}
+
+static int
+stub_cred_check_relabel(struct ucred *cred, struct label *newlabel)
+{
+
+ return (0);
+}
+
+static int
+stub_cred_check_visible(struct ucred *cr1, struct ucred *cr2)
+{
+
+ return (0);
+}
+
+static void
+stub_cred_create_init(struct ucred *cred)
+{
+
+}
+
+static void
+stub_cred_create_swapper(struct ucred *cred)
+{
+
+}
+
+static void
+stub_cred_relabel(struct ucred *cred, struct label *newlabel)
+{
+
+}
+
+static void
+stub_devfs_create_device(struct ucred *cred, struct mount *mp,
+ struct cdev *dev, struct devfs_dirent *de, struct label *delabel)
+{
+
+}
+
+static void
+stub_devfs_create_directory(struct mount *mp, char *dirname,
+ int dirnamelen, struct devfs_dirent *de, struct label *delabel)
+{
+
+}
+
+static void
+stub_devfs_create_symlink(struct ucred *cred, struct mount *mp,
+ struct devfs_dirent *dd, struct label *ddlabel, struct devfs_dirent *de,
+ struct label *delabel)
+{
+
+}
+
+static void
+stub_devfs_update(struct mount *mp, struct devfs_dirent *de,
+ struct label *delabel, struct vnode *vp, struct label *vplabel)
+{
+
+}
+
+static void
+stub_devfs_vnode_associate(struct mount *mp, struct label *mplabel,
+ struct devfs_dirent *de, struct label *delabel, struct vnode *vp,
+ struct label *vplabel)
+{
+
+}
+
+static int
+stub_ifnet_check_relabel(struct ucred *cred, struct ifnet *ifp,
+ struct label *ifplabel, struct label *newlabel)
+{
+
+ return (0);
+}
+
+static int
+stub_ifnet_check_transmit(struct ifnet *ifp, struct label *ifplabel,
+ struct mbuf *m, struct label *mlabel)
+{
+
+ return (0);
+}
+
+static void
+stub_ifnet_create(struct ifnet *ifp, struct label *ifplabel)
+{
+
+}
+
+static void
+stub_ifnet_create_mbuf(struct ifnet *ifp, struct label *ifplabel,
+ struct mbuf *m, struct label *mlabel)
+{
+
+}
+
+static void
+stub_ifnet_relabel(struct ucred *cred, struct ifnet *ifp,
+ struct label *ifplabel, struct label *newlabel)
+{
+
+}
+
+static int
+stub_inpcb_check_deliver(struct inpcb *inp, struct label *inplabel,
+ struct mbuf *m, struct label *mlabel)
+{
+
+ return (0);
+}
+
+static void
+stub_inpcb_create(struct socket *so, struct label *solabel,
+ struct inpcb *inp, struct label *inplabel)
+{
+
+}
+
+static void
+stub_inpcb_create_mbuf(struct inpcb *inp, struct label *inplabel,
+ struct mbuf *m, struct label *mlabel)
+{
+
+}
+
+static void
+stub_inpcb_sosetlabel(struct socket *so, struct label *solabel,
+ struct inpcb *inp, struct label *inplabel)
+{
+
+}
+
+static void
+stub_ip6q_create(struct mbuf *m, struct label *mlabel, struct ip6q *q6,
+ struct label *q6label)
+{
+
+}
+
+static int
+stub_ip6q_match(struct mbuf *m, struct label *mlabel, struct ip6q *q6,
+ struct label *q6label)
+{
+
+ return (1);
+}
+
+static void
+stub_ip6q_reassemble(struct ip6q *q6, struct label *q6label, struct mbuf *m,
+ struct label *mlabel)
+{
+
+}
+
+static void
+stub_ip6q_update(struct mbuf *m, struct label *mlabel, struct ip6q *q6,
+ struct label *q6label)
+{
+
+}
+
+static void
+stub_ipq_create(struct mbuf *m, struct label *mlabel, struct ipq *q,
+ struct label *qlabel)
+{
+
+}
+
+static int
+stub_ipq_match(struct mbuf *m, struct label *mlabel, struct ipq *q,
+ struct label *qlabel)
+{
+
+ return (1);
+}
+
+static void
+stub_ipq_reassemble(struct ipq *q, struct label *qlabel, struct mbuf *m,
+ struct label *mlabel)
+{
+
+}
+
+static void
+stub_ipq_update(struct mbuf *m, struct label *mlabel, struct ipq *q,
+ struct label *qlabel)
+{
+
+}
+
+static int
+stub_kenv_check_dump(struct ucred *cred)
+{
+
+ return (0);
+}
+
+static int
+stub_kenv_check_get(struct ucred *cred, char *name)
+{
+
+ return (0);
+}
+
+static int
+stub_kenv_check_set(struct ucred *cred, char *name, char *value)
+{
+
+ return (0);
+}
+
+static int
+stub_kenv_check_unset(struct ucred *cred, char *name)
+{
+
+ return (0);
+}
+
+static int
+stub_kld_check_load(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel)
+{
+
+ return (0);
+}
+
+static int
+stub_kld_check_stat(struct ucred *cred)
+{
+
+ return (0);
+}
+
+static int
+stub_mount_check_stat(struct ucred *cred, struct mount *mp,
+ struct label *mplabel)
+{
+
+ return (0);
+}
+
+static void
+stub_mount_create(struct ucred *cred, struct mount *mp,
+ struct label *mplabel)
+{
+
+}
+
+static void
+stub_netatalk_aarp_send(struct ifnet *ifp, struct label *iflpabel,
+ struct mbuf *m, struct label *mlabel)
+{
+
+}
+
+static void
+stub_netinet_arp_send(struct ifnet *ifp, struct label *iflpabel,
+ struct mbuf *m, struct label *mlabel)
+{
+
+}
+
+static void
+stub_netinet_firewall_reply(struct mbuf *mrecv, struct label *mrecvlabel,
+ struct mbuf *msend, struct label *msendlabel)
+{
+
+}
+
+static void
+stub_netinet_firewall_send(struct mbuf *m, struct label *mlabel)
+{
+
+}
+
+static void
+stub_netinet_fragment(struct mbuf *m, struct label *mlabel, struct mbuf *frag,
+ struct label *fraglabel)
+{
+
+}
+
+static void
+stub_netinet_icmp_reply(struct mbuf *mrecv, struct label *mrecvlabel,
+ struct mbuf *msend, struct label *msendlabel)
+{
+
+}
+
+static void
+stub_netinet_icmp_replyinplace(struct mbuf *m, struct label *mlabel)
+{
+
+}
+
+static void
+stub_netinet_igmp_send(struct ifnet *ifp, struct label *iflpabel,
+ struct mbuf *m, struct label *mlabel)
+{
+
+}
+
+static void
+stub_netinet_tcp_reply(struct mbuf *m, struct label *mlabel)
+{
+
+}
+
+static void
+stub_netinet6_nd6_send(struct ifnet *ifp, struct label *iflpabel,
+ struct mbuf *m, struct label *mlabel)
+{
+
+}
+
+static int
+stub_pipe_check_ioctl(struct ucred *cred, struct pipepair *pp,
+ struct label *pplabel, unsigned long cmd, void /* caddr_t */ *data)
+{
+
+ return (0);
+}
+
+static int
+stub_pipe_check_poll(struct ucred *cred, struct pipepair *pp,
+ struct label *pplabel)
+{
+
+ return (0);
+}
+
+static int
+stub_pipe_check_read(struct ucred *cred, struct pipepair *pp,
+ struct label *pplabel)
+{
+
+ return (0);
+}
+
+static int
+stub_pipe_check_relabel(struct ucred *cred, struct pipepair *pp,
+ struct label *pplabel, struct label *newlabel)
+{
+
+ return (0);
+}
+
+static int
+stub_pipe_check_stat(struct ucred *cred, struct pipepair *pp,
+ struct label *pplabel)
+{
+
+ return (0);
+}
+
+static int
+stub_pipe_check_write(struct ucred *cred, struct pipepair *pp,
+ struct label *pplabel)
+{
+
+ return (0);
+}
+
+static void
+stub_pipe_create(struct ucred *cred, struct pipepair *pp,
+ struct label *pplabel)
+{
+
+}
+
+static void
+stub_pipe_relabel(struct ucred *cred, struct pipepair *pp,
+ struct label *pplabel, struct label *newlabel)
+{
+
+}
+
+static int
+stub_posixsem_check_getvalue(struct ucred *active_cred, struct ucred *file_cred,
+ struct ksem *ks, struct label *kslabel)
+{
+
+ return (0);
+}
+
+static int
+stub_posixsem_check_open(struct ucred *cred, struct ksem *ks,
+ struct label *kslabel)
+{
+
+ return (0);
+}
+
+static int
+stub_posixsem_check_post(struct ucred *active_cred, struct ucred *file_cred,
+ struct ksem *ks, struct label *kslabel)
+{
+
+ return (0);
+}
+
+static int
+stub_posixsem_check_stat(struct ucred *active_cred, struct ucred *file_cred,
+ struct ksem *ks, struct label *kslabel)
+{
+
+ return (0);
+}
+
+static int
+stub_posixsem_check_unlink(struct ucred *cred, struct ksem *ks,
+ struct label *kslabel)
+{
+
+ return (0);
+}
+
+static int
+stub_posixsem_check_wait(struct ucred *active_cred, struct ucred *file_cred,
+ struct ksem *ks, struct label *kslabel)
+{
+
+ return (0);
+}
+
+static void
+stub_posixsem_create(struct ucred *cred, struct ksem *ks,
+ struct label *kslabel)
+{
+
+}
+
+static int
+stub_posixshm_check_mmap(struct ucred *cred, struct shmfd *shmfd,
+ struct label *shmlabel, int prot, int flags)
+{
+
+ return (0);
+}
+
+static int
+stub_posixshm_check_open(struct ucred *cred, struct shmfd *shmfd,
+ struct label *shmlabel)
+{
+
+ return (0);
+}
+
+static int
+stub_posixshm_check_stat(struct ucred *active_cred, struct ucred *file_cred,
+ struct shmfd *shmfd, struct label *shmlabel)
+{
+
+ return (0);
+}
+
+static int
+stub_posixshm_check_truncate(struct ucred *active_cred,
+ struct ucred *file_cred, struct shmfd *shmfd, struct label *shmlabel)
+{
+
+ return (0);
+}
+
+static int
+stub_posixshm_check_unlink(struct ucred *cred, struct shmfd *shmfd,
+ struct label *shmlabel)
+{
+
+ return (0);
+}
+
+static void
+stub_posixshm_create(struct ucred *cred, struct shmfd *shmfd,
+ struct label *shmlabel)
+{
+
+}
+
+static int
+stub_priv_check(struct ucred *cred, int priv)
+{
+
+ return (0);
+}
+
+static int
+stub_priv_grant(struct ucred *cred, int priv)
+{
+
+ return (EPERM);
+}
+
+static int
+stub_proc_check_debug(struct ucred *cred, struct proc *p)
+{
+
+ return (0);
+}
+
+static int
+stub_proc_check_sched(struct ucred *cred, struct proc *p)
+{
+
+ return (0);
+}
+
+static int
+stub_proc_check_setaudit(struct ucred *cred, struct auditinfo *ai)
+{
+
+ return (0);
+}
+
+static int
+stub_proc_check_setaudit_addr(struct ucred *cred, struct auditinfo_addr *aia)
+{
+
+ return (0);
+}
+
+static int
+stub_proc_check_setauid(struct ucred *cred, uid_t auid)
+{
+
+ return (0);
+}
+
+static int
+stub_proc_check_setegid(struct ucred *cred, gid_t egid)
+{
+
+ return (0);
+}
+
+static int
+stub_proc_check_seteuid(struct ucred *cred, uid_t euid)
+{
+
+ return (0);
+}
+
+static int
+stub_proc_check_setgid(struct ucred *cred, gid_t gid)
+{
+
+ return (0);
+}
+
+static int
+stub_proc_check_setgroups(struct ucred *cred, int ngroups,
+ gid_t *gidset)
+{
+
+ return (0);
+}
+
+static int
+stub_proc_check_setregid(struct ucred *cred, gid_t rgid, gid_t egid)
+{
+
+ return (0);
+}
+
+static int
+stub_proc_check_setresgid(struct ucred *cred, gid_t rgid, gid_t egid,
+ gid_t sgid)
+{
+
+ return (0);
+}
+
+static int
+stub_proc_check_setresuid(struct ucred *cred, uid_t ruid, uid_t euid,
+ uid_t suid)
+{
+
+ return (0);
+}
+
+static int
+stub_proc_check_setreuid(struct ucred *cred, uid_t ruid, uid_t euid)
+{
+
+ return (0);
+}
+
+static int
+stub_proc_check_setuid(struct ucred *cred, uid_t uid)
+{
+
+ return (0);
+}
+
+static int
+stub_proc_check_signal(struct ucred *cred, struct proc *p, int signum)
+{
+
+ return (0);
+}
+
+static int
+stub_proc_check_wait(struct ucred *cred, struct proc *p)
+{
+
+ return (0);
+}
+
+static int
+stub_socket_check_accept(struct ucred *cred, struct socket *so,
+ struct label *solabel)
+{
+
+ return (0);
+}
+
+static int
+stub_socket_check_bind(struct ucred *cred, struct socket *so,
+ struct label *solabel, struct sockaddr *sa)
+{
+
+ return (0);
+}
+
+static int
+stub_socket_check_connect(struct ucred *cred, struct socket *so,
+ struct label *solabel, struct sockaddr *sa)
+{
+
+ return (0);
+}
+
+static int
+stub_socket_check_create(struct ucred *cred, int domain, int type, int proto)
+{
+
+ return (0);
+}
+
+static int
+stub_socket_check_deliver(struct socket *so, struct label *solabel,
+ struct mbuf *m, struct label *mlabel)
+{
+
+ return (0);
+}
+
+static int
+stub_socket_check_listen(struct ucred *cred, struct socket *so,
+ struct label *solabel)
+{
+
+ return (0);
+}
+
+static int
+stub_socket_check_poll(struct ucred *cred, struct socket *so,
+ struct label *solabel)
+{
+
+ return (0);
+}
+
+static int
+stub_socket_check_receive(struct ucred *cred, struct socket *so,
+ struct label *solabel)
+{
+
+ return (0);
+}
+
+static int
+stub_socket_check_relabel(struct ucred *cred, struct socket *so,
+ struct label *solabel, struct label *newlabel)
+{
+
+ return (0);
+}
+static int
+stub_socket_check_send(struct ucred *cred, struct socket *so,
+ struct label *solabel)
+{
+
+ return (0);
+}
+
+static int
+stub_socket_check_stat(struct ucred *cred, struct socket *so,
+ struct label *solabel)
+{
+
+ return (0);
+}
+
+static int
+stub_inpcb_check_visible(struct ucred *cred, struct inpcb *inp,
+ struct label *inplabel)
+{
+
+ return (0);
+}
+
+static int
+stub_socket_check_visible(struct ucred *cred, struct socket *so,
+ struct label *solabel)
+{
+
+ return (0);
+}
+
+static void
+stub_socket_create(struct ucred *cred, struct socket *so,
+ struct label *solabel)
+{
+
+}
+
+static void
+stub_socket_create_mbuf(struct socket *so, struct label *solabel,
+ struct mbuf *m, struct label *mlabel)
+{
+
+}
+
+static void
+stub_socket_newconn(struct socket *oldso, struct label *oldsolabel,
+ struct socket *newso, struct label *newsolabel)
+{
+
+}
+
+static void
+stub_socket_relabel(struct ucred *cred, struct socket *so,
+ struct label *solabel, struct label *newlabel)
+{
+
+}
+
+static void
+stub_socketpeer_set_from_mbuf(struct mbuf *m, struct label *mlabel,
+ struct socket *so, struct label *sopeerlabel)
+{
+
+}
+
+static void
+stub_socketpeer_set_from_socket(struct socket *oldso,
+ struct label *oldsolabel, struct socket *newso,
+ struct label *newsopeerlabel)
+{
+
+}
+
+static void
+stub_syncache_create(struct label *label, struct inpcb *inp)
+{
+
+}
+
+static void
+stub_syncache_create_mbuf(struct label *sc_label, struct mbuf *m,
+ struct label *mlabel)
+{
+
+}
+
+static int
+stub_system_check_acct(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel)
+{
+
+ return (0);
+}
+
+static int
+stub_system_check_audit(struct ucred *cred, void *record, int length)
+{
+
+ return (0);
+}
+
+static int
+stub_system_check_auditctl(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel)
+{
+
+ return (0);
+}
+
+static int
+stub_system_check_auditon(struct ucred *cred, int cmd)
+{
+
+ return (0);
+}
+
+static int
+stub_system_check_reboot(struct ucred *cred, int how)
+{
+
+ return (0);
+}
+
+static int
+stub_system_check_swapoff(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel)
+{
+
+ return (0);
+}
+
+static int
+stub_system_check_swapon(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel)
+{
+
+ return (0);
+}
+
+static int
+stub_system_check_sysctl(struct ucred *cred, struct sysctl_oid *oidp,
+ void *arg1, int arg2, struct sysctl_req *req)
+{
+
+ return (0);
+}
+
+static void
+stub_sysvmsg_cleanup(struct label *msglabel)
+{
+
+}
+
+static void
+stub_sysvmsg_create(struct ucred *cred, struct msqid_kernel *msqkptr,
+ struct label *msqlabel, struct msg *msgptr, struct label *msglabel)
+{
+
+}
+
+static int
+stub_sysvmsq_check_msgmsq(struct ucred *cred, struct msg *msgptr,
+ struct label *msglabel, struct msqid_kernel *msqkptr,
+ struct label *msqklabel)
+{
+
+ return (0);
+}
+
+static int
+stub_sysvmsq_check_msgrcv(struct ucred *cred, struct msg *msgptr,
+ struct label *msglabel)
+{
+
+ return (0);
+}
+
+
+static int
+stub_sysvmsq_check_msgrmid(struct ucred *cred, struct msg *msgptr,
+ struct label *msglabel)
+{
+
+ return (0);
+}
+
+
+static int
+stub_sysvmsq_check_msqget(struct ucred *cred, struct msqid_kernel *msqkptr,
+ struct label *msqklabel)
+{
+
+ return (0);
+}
+
+
+static int
+stub_sysvmsq_check_msqsnd(struct ucred *cred, struct msqid_kernel *msqkptr,
+ struct label *msqklabel)
+{
+
+ return (0);
+}
+
+static int
+stub_sysvmsq_check_msqrcv(struct ucred *cred, struct msqid_kernel *msqkptr,
+ struct label *msqklabel)
+{
+
+ return (0);
+}
+
+
+static int
+stub_sysvmsq_check_msqctl(struct ucred *cred, struct msqid_kernel *msqkptr,
+ struct label *msqklabel, int cmd)
+{
+
+ return (0);
+}
+
+
+static void
+stub_sysvmsq_cleanup(struct label *msqlabel)
+{
+
+}
+
+static void
+stub_sysvmsq_create(struct ucred *cred, struct msqid_kernel *msqkptr,
+ struct label *msqlabel)
+{
+
+}
+
+static int
+stub_sysvsem_check_semctl(struct ucred *cred, struct semid_kernel *semakptr,
+ struct label *semaklabel, int cmd)
+{
+
+ return (0);
+}
+
+static int
+stub_sysvsem_check_semget(struct ucred *cred, struct semid_kernel *semakptr,
+ struct label *semaklabel)
+{
+
+ return (0);
+}
+
+
+static int
+stub_sysvsem_check_semop(struct ucred *cred, struct semid_kernel *semakptr,
+ struct label *semaklabel, size_t accesstype)
+{
+
+ return (0);
+}
+
+static void
+stub_sysvsem_cleanup(struct label *semalabel)
+{
+
+}
+
+static void
+stub_sysvsem_create(struct ucred *cred, struct semid_kernel *semakptr,
+ struct label *semalabel)
+{
+
+}
+
+static int
+stub_sysvshm_check_shmat(struct ucred *cred, struct shmid_kernel *shmsegptr,
+ struct label *shmseglabel, int shmflg)
+{
+
+ return (0);
+}
+
+static int
+stub_sysvshm_check_shmctl(struct ucred *cred, struct shmid_kernel *shmsegptr,
+ struct label *shmseglabel, int cmd)
+{
+
+ return (0);
+}
+
+static int
+stub_sysvshm_check_shmdt(struct ucred *cred, struct shmid_kernel *shmsegptr,
+ struct label *shmseglabel)
+{
+
+ return (0);
+}
+
+
+static int
+stub_sysvshm_check_shmget(struct ucred *cred, struct shmid_kernel *shmsegptr,
+ struct label *shmseglabel, int shmflg)
+{
+
+ return (0);
+}
+
+static void
+stub_sysvshm_cleanup(struct label *shmlabel)
+{
+
+}
+
+static void
+stub_sysvshm_create(struct ucred *cred, struct shmid_kernel *shmsegptr,
+ struct label *shmalabel)
+{
+
+}
+
+static void
+stub_thread_userret(struct thread *td)
+{
+
+}
+
+static int
+stub_vnode_associate_extattr(struct mount *mp, struct label *mplabel,
+ struct vnode *vp, struct label *vplabel)
+{
+
+ return (0);
+}
+
+static void
+stub_vnode_associate_singlelabel(struct mount *mp, struct label *mplabel,
+ struct vnode *vp, struct label *vplabel)
+{
+
+}
+
+static int
+stub_vnode_check_access(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, accmode_t accmode)
+{
+
+ return (0);
+}
+
+static int
+stub_vnode_check_chdir(struct ucred *cred, struct vnode *dvp,
+ struct label *dvplabel)
+{
+
+ return (0);
+}
+
+static int
+stub_vnode_check_chroot(struct ucred *cred, struct vnode *dvp,
+ struct label *dvplabel)
+{
+
+ return (0);
+}
+
+static int
+stub_vnode_check_create(struct ucred *cred, struct vnode *dvp,
+ struct label *dvplabel, struct componentname *cnp, struct vattr *vap)
+{
+
+ return (0);
+}
+
+static int
+stub_vnode_check_deleteacl(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, acl_type_t type)
+{
+
+ return (0);
+}
+
+static int
+stub_vnode_check_deleteextattr(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, int attrnamespace, const char *name)
+{
+
+ return (0);
+}
+
+static int
+stub_vnode_check_exec(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, struct image_params *imgp,
+ struct label *execlabel)
+{
+
+ return (0);
+}
+
+static int
+stub_vnode_check_getacl(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, acl_type_t type)
+{
+
+ return (0);
+}
+
+static int
+stub_vnode_check_getextattr(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, int attrnamespace, const char *name,
+ struct uio *uio)
+{
+
+ return (0);
+}
+
+static int
+stub_vnode_check_link(struct ucred *cred, struct vnode *dvp,
+ struct label *dvplabel, struct vnode *vp, struct label *vplabel,
+ struct componentname *cnp)
+{
+
+ return (0);
+}
+
+static int
+stub_vnode_check_listextattr(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, int attrnamespace)
+{
+
+ return (0);
+}
+
+static int
+stub_vnode_check_lookup(struct ucred *cred, struct vnode *dvp,
+ struct label *dvplabel, struct componentname *cnp)
+{
+
+ return (0);
+}
+
+static int
+stub_vnode_check_mmap(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, int prot, int flags)
+{
+
+ return (0);
+}
+
+static void
+stub_vnode_check_mmap_downgrade(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, int *prot)
+{
+
+}
+
+static int
+stub_vnode_check_mprotect(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, int prot)
+{
+
+ return (0);
+}
+
+static int
+stub_vnode_check_open(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, accmode_t accmode)
+{
+
+ return (0);
+}
+
+static int
+stub_vnode_check_poll(struct ucred *active_cred, struct ucred *file_cred,
+ struct vnode *vp, struct label *vplabel)
+{
+
+ return (0);
+}
+
+static int
+stub_vnode_check_read(struct ucred *active_cred, struct ucred *file_cred,
+ struct vnode *vp, struct label *vplabel)
+{
+
+ return (0);
+}
+
+static int
+stub_vnode_check_readdir(struct ucred *cred, struct vnode *vp,
+ struct label *dvplabel)
+{
+
+ return (0);
+}
+
+static int
+stub_vnode_check_readlink(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel)
+{
+
+ return (0);
+}
+
+static int
+stub_vnode_check_relabel(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, struct label *newlabel)
+{
+
+ return (0);
+}
+
+static int
+stub_vnode_check_rename_from(struct ucred *cred, struct vnode *dvp,
+ struct label *dvplabel, struct vnode *vp, struct label *vplabel,
+ struct componentname *cnp)
+{
+
+ return (0);
+}
+
+static int
+stub_vnode_check_rename_to(struct ucred *cred, struct vnode *dvp,
+ struct label *dvplabel, struct vnode *vp, struct label *vplabel,
+ int samedir, struct componentname *cnp)
+{
+
+ return (0);
+}
+
+static int
+stub_vnode_check_revoke(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel)
+{
+
+ return (0);
+}
+
+static int
+stub_vnode_check_setacl(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, acl_type_t type, struct acl *acl)
+{
+
+ return (0);
+}
+
+static int
+stub_vnode_check_setextattr(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, int attrnamespace, const char *name,
+ struct uio *uio)
+{
+
+ return (0);
+}
+
+static int
+stub_vnode_check_setflags(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, u_long flags)
+{
+
+ return (0);
+}
+
+static int
+stub_vnode_check_setmode(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, mode_t mode)
+{
+
+ return (0);
+}
+
+static int
+stub_vnode_check_setowner(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, uid_t uid, gid_t gid)
+{
+
+ return (0);
+}
+
+static int
+stub_vnode_check_setutimes(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, struct timespec atime, struct timespec mtime)
+{
+
+ return (0);
+}
+
+static int
+stub_vnode_check_stat(struct ucred *active_cred, struct ucred *file_cred,
+ struct vnode *vp, struct label *vplabel)
+{
+
+ return (0);
+}
+
+static int
+stub_vnode_check_unlink(struct ucred *cred, struct vnode *dvp,
+ struct label *dvplabel, struct vnode *vp, struct label *vplabel,
+ struct componentname *cnp)
+{
+
+ return (0);
+}
+
+static int
+stub_vnode_check_write(struct ucred *active_cred, struct ucred *file_cred,
+ struct vnode *vp, struct label *vplabel)
+{
+
+ return (0);
+}
+
+static int
+stub_vnode_create_extattr(struct ucred *cred, struct mount *mp,
+ struct label *mntlabel, struct vnode *dvp, struct label *dvplabel,
+ struct vnode *vp, struct label *vplabel, struct componentname *cnp)
+{
+
+ return (0);
+}
+
+static void
+stub_vnode_execve_transition(struct ucred *old, struct ucred *new,
+ struct vnode *vp, struct label *vplabel, struct label *interpvplabel,
+ struct image_params *imgp, struct label *execlabel)
+{
+
+}
+
+static int
+stub_vnode_execve_will_transition(struct ucred *old, struct vnode *vp,
+ struct label *vplabel, struct label *interpvplabel,
+ struct image_params *imgp, struct label *execlabel)
+{
+
+ return (0);
+}
+
+static void
+stub_vnode_relabel(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, struct label *label)
+{
+
+}
+
+static int
+stub_vnode_setlabel_extattr(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, struct label *intlabel)
+{
+
+ return (0);
+}
+
+/*
+ * Register functions with MAC Framework policy entry points.
+ */
+static struct mac_policy_ops stub_ops =
+{
+ .mpo_destroy = stub_destroy,
+ .mpo_init = stub_init,
+ .mpo_syscall = stub_syscall,
+
+ .mpo_bpfdesc_check_receive = stub_bpfdesc_check_receive,
+ .mpo_bpfdesc_create = stub_bpfdesc_create,
+ .mpo_bpfdesc_create_mbuf = stub_bpfdesc_create_mbuf,
+ .mpo_bpfdesc_destroy_label = stub_destroy_label,
+ .mpo_bpfdesc_init_label = stub_init_label,
+
+ .mpo_cred_associate_nfsd = stub_cred_associate_nfsd,
+ .mpo_cred_check_relabel = stub_cred_check_relabel,
+ .mpo_cred_check_visible = stub_cred_check_visible,
+ .mpo_cred_copy_label = stub_copy_label,
+ .mpo_cred_create_init = stub_cred_create_init,
+ .mpo_cred_create_swapper = stub_cred_create_swapper,
+ .mpo_cred_destroy_label = stub_destroy_label,
+ .mpo_cred_externalize_label = stub_externalize_label,
+ .mpo_cred_init_label = stub_init_label,
+ .mpo_cred_internalize_label = stub_internalize_label,
+ .mpo_cred_relabel= stub_cred_relabel,
+
+ .mpo_devfs_create_device = stub_devfs_create_device,
+ .mpo_devfs_create_directory = stub_devfs_create_directory,
+ .mpo_devfs_create_symlink = stub_devfs_create_symlink,
+ .mpo_devfs_destroy_label = stub_destroy_label,
+ .mpo_devfs_init_label = stub_init_label,
+ .mpo_devfs_update = stub_devfs_update,
+ .mpo_devfs_vnode_associate = stub_devfs_vnode_associate,
+
+ .mpo_ifnet_check_relabel = stub_ifnet_check_relabel,
+ .mpo_ifnet_check_transmit = stub_ifnet_check_transmit,
+ .mpo_ifnet_copy_label = stub_copy_label,
+ .mpo_ifnet_create = stub_ifnet_create,
+ .mpo_ifnet_create_mbuf = stub_ifnet_create_mbuf,
+ .mpo_ifnet_destroy_label = stub_destroy_label,
+ .mpo_ifnet_externalize_label = stub_externalize_label,
+ .mpo_ifnet_init_label = stub_init_label,
+ .mpo_ifnet_internalize_label = stub_internalize_label,
+ .mpo_ifnet_relabel = stub_ifnet_relabel,
+
+ .mpo_inpcb_check_deliver = stub_inpcb_check_deliver,
+ .mpo_inpcb_check_visible = stub_inpcb_check_visible,
+ .mpo_inpcb_create = stub_inpcb_create,
+ .mpo_inpcb_create_mbuf = stub_inpcb_create_mbuf,
+ .mpo_inpcb_destroy_label = stub_destroy_label,
+ .mpo_inpcb_init_label = stub_init_label_waitcheck,
+ .mpo_inpcb_sosetlabel = stub_inpcb_sosetlabel,
+
+ .mpo_ip6q_create = stub_ip6q_create,
+ .mpo_ip6q_destroy_label = stub_destroy_label,
+ .mpo_ip6q_init_label = stub_init_label_waitcheck,
+ .mpo_ip6q_match = stub_ip6q_match,
+ .mpo_ip6q_update = stub_ip6q_update,
+ .mpo_ip6q_reassemble = stub_ip6q_reassemble,
+
+ .mpo_ipq_create = stub_ipq_create,
+ .mpo_ipq_destroy_label = stub_destroy_label,
+ .mpo_ipq_init_label = stub_init_label_waitcheck,
+ .mpo_ipq_match = stub_ipq_match,
+ .mpo_ipq_update = stub_ipq_update,
+ .mpo_ipq_reassemble = stub_ipq_reassemble,
+
+ .mpo_kenv_check_dump = stub_kenv_check_dump,
+ .mpo_kenv_check_get = stub_kenv_check_get,
+ .mpo_kenv_check_set = stub_kenv_check_set,
+ .mpo_kenv_check_unset = stub_kenv_check_unset,
+
+ .mpo_kld_check_load = stub_kld_check_load,
+ .mpo_kld_check_stat = stub_kld_check_stat,
+
+ .mpo_mbuf_copy_label = stub_copy_label,
+ .mpo_mbuf_destroy_label = stub_destroy_label,
+ .mpo_mbuf_init_label = stub_init_label_waitcheck,
+
+ .mpo_mount_check_stat = stub_mount_check_stat,
+ .mpo_mount_create = stub_mount_create,
+ .mpo_mount_destroy_label = stub_destroy_label,
+ .mpo_mount_init_label = stub_init_label,
+
+ .mpo_netatalk_aarp_send = stub_netatalk_aarp_send,
+
+ .mpo_netinet_arp_send = stub_netinet_arp_send,
+ .mpo_netinet_firewall_reply = stub_netinet_firewall_reply,
+ .mpo_netinet_firewall_send = stub_netinet_firewall_send,
+ .mpo_netinet_fragment = stub_netinet_fragment,
+ .mpo_netinet_icmp_reply = stub_netinet_icmp_reply,
+ .mpo_netinet_icmp_replyinplace = stub_netinet_icmp_replyinplace,
+ .mpo_netinet_tcp_reply = stub_netinet_tcp_reply,
+ .mpo_netinet_igmp_send = stub_netinet_igmp_send,
+
+ .mpo_netinet6_nd6_send = stub_netinet6_nd6_send,
+
+ .mpo_pipe_check_ioctl = stub_pipe_check_ioctl,
+ .mpo_pipe_check_poll = stub_pipe_check_poll,
+ .mpo_pipe_check_read = stub_pipe_check_read,
+ .mpo_pipe_check_relabel = stub_pipe_check_relabel,
+ .mpo_pipe_check_stat = stub_pipe_check_stat,
+ .mpo_pipe_check_write = stub_pipe_check_write,
+ .mpo_pipe_copy_label = stub_copy_label,
+ .mpo_pipe_create = stub_pipe_create,
+ .mpo_pipe_destroy_label = stub_destroy_label,
+ .mpo_pipe_externalize_label = stub_externalize_label,
+ .mpo_pipe_init_label = stub_init_label,
+ .mpo_pipe_internalize_label = stub_internalize_label,
+ .mpo_pipe_relabel = stub_pipe_relabel,
+
+ .mpo_posixsem_check_getvalue = stub_posixsem_check_getvalue,
+ .mpo_posixsem_check_open = stub_posixsem_check_open,
+ .mpo_posixsem_check_post = stub_posixsem_check_post,
+ .mpo_posixsem_check_stat = stub_posixsem_check_stat,
+ .mpo_posixsem_check_unlink = stub_posixsem_check_unlink,
+ .mpo_posixsem_check_wait = stub_posixsem_check_wait,
+ .mpo_posixsem_create = stub_posixsem_create,
+ .mpo_posixsem_destroy_label = stub_destroy_label,
+ .mpo_posixsem_init_label = stub_init_label,
+
+ .mpo_posixshm_check_mmap = stub_posixshm_check_mmap,
+ .mpo_posixshm_check_open = stub_posixshm_check_open,
+ .mpo_posixshm_check_stat = stub_posixshm_check_stat,
+ .mpo_posixshm_check_truncate = stub_posixshm_check_truncate,
+ .mpo_posixshm_check_unlink = stub_posixshm_check_unlink,
+ .mpo_posixshm_create = stub_posixshm_create,
+ .mpo_posixshm_destroy_label = stub_destroy_label,
+ .mpo_posixshm_init_label = stub_init_label,
+
+ .mpo_priv_check = stub_priv_check,
+ .mpo_priv_grant = stub_priv_grant,
+
+ .mpo_proc_check_debug = stub_proc_check_debug,
+ .mpo_proc_check_sched = stub_proc_check_sched,
+ .mpo_proc_check_setaudit = stub_proc_check_setaudit,
+ .mpo_proc_check_setaudit_addr = stub_proc_check_setaudit_addr,
+ .mpo_proc_check_setauid = stub_proc_check_setauid,
+ .mpo_proc_check_setegid = stub_proc_check_setegid,
+ .mpo_proc_check_seteuid = stub_proc_check_seteuid,
+ .mpo_proc_check_setgid = stub_proc_check_setgid,
+ .mpo_proc_check_setgroups = stub_proc_check_setgroups,
+ .mpo_proc_check_setregid = stub_proc_check_setregid,
+ .mpo_proc_check_setresgid = stub_proc_check_setresgid,
+ .mpo_proc_check_setresuid = stub_proc_check_setresuid,
+ .mpo_proc_check_setreuid = stub_proc_check_setreuid,
+ .mpo_proc_check_setuid = stub_proc_check_setuid,
+ .mpo_proc_check_signal = stub_proc_check_signal,
+ .mpo_proc_check_wait = stub_proc_check_wait,
+
+ .mpo_socket_check_accept = stub_socket_check_accept,
+ .mpo_socket_check_bind = stub_socket_check_bind,
+ .mpo_socket_check_connect = stub_socket_check_connect,
+ .mpo_socket_check_create = stub_socket_check_create,
+ .mpo_socket_check_deliver = stub_socket_check_deliver,
+ .mpo_socket_check_listen = stub_socket_check_listen,
+ .mpo_socket_check_poll = stub_socket_check_poll,
+ .mpo_socket_check_receive = stub_socket_check_receive,
+ .mpo_socket_check_relabel = stub_socket_check_relabel,
+ .mpo_socket_check_send = stub_socket_check_send,
+ .mpo_socket_check_stat = stub_socket_check_stat,
+ .mpo_socket_check_visible = stub_socket_check_visible,
+ .mpo_socket_copy_label = stub_copy_label,
+ .mpo_socket_create = stub_socket_create,
+ .mpo_socket_create_mbuf = stub_socket_create_mbuf,
+ .mpo_socket_destroy_label = stub_destroy_label,
+ .mpo_socket_externalize_label = stub_externalize_label,
+ .mpo_socket_init_label = stub_init_label_waitcheck,
+ .mpo_socket_internalize_label = stub_internalize_label,
+ .mpo_socket_newconn = stub_socket_newconn,
+ .mpo_socket_relabel = stub_socket_relabel,
+
+ .mpo_socketpeer_destroy_label = stub_destroy_label,
+ .mpo_socketpeer_externalize_label = stub_externalize_label,
+ .mpo_socketpeer_init_label = stub_init_label_waitcheck,
+ .mpo_socketpeer_set_from_mbuf = stub_socketpeer_set_from_mbuf,
+ .mpo_socketpeer_set_from_socket = stub_socketpeer_set_from_socket,
+
+ .mpo_syncache_init_label = stub_init_label_waitcheck,
+ .mpo_syncache_destroy_label = stub_destroy_label,
+ .mpo_syncache_create = stub_syncache_create,
+ .mpo_syncache_create_mbuf= stub_syncache_create_mbuf,
+
+ .mpo_sysvmsg_cleanup = stub_sysvmsg_cleanup,
+ .mpo_sysvmsg_create = stub_sysvmsg_create,
+ .mpo_sysvmsg_destroy_label = stub_destroy_label,
+ .mpo_sysvmsg_init_label = stub_init_label,
+
+ .mpo_sysvmsq_check_msgmsq = stub_sysvmsq_check_msgmsq,
+ .mpo_sysvmsq_check_msgrcv = stub_sysvmsq_check_msgrcv,
+ .mpo_sysvmsq_check_msgrmid = stub_sysvmsq_check_msgrmid,
+ .mpo_sysvmsq_check_msqget = stub_sysvmsq_check_msqget,
+ .mpo_sysvmsq_check_msqsnd = stub_sysvmsq_check_msqsnd,
+ .mpo_sysvmsq_check_msqrcv = stub_sysvmsq_check_msqrcv,
+ .mpo_sysvmsq_check_msqctl = stub_sysvmsq_check_msqctl,
+ .mpo_sysvmsq_cleanup = stub_sysvmsq_cleanup,
+ .mpo_sysvmsq_create = stub_sysvmsq_create,
+ .mpo_sysvmsq_destroy_label = stub_destroy_label,
+ .mpo_sysvmsq_init_label = stub_init_label,
+
+ .mpo_sysvsem_check_semctl = stub_sysvsem_check_semctl,
+ .mpo_sysvsem_check_semget = stub_sysvsem_check_semget,
+ .mpo_sysvsem_check_semop = stub_sysvsem_check_semop,
+ .mpo_sysvsem_cleanup = stub_sysvsem_cleanup,
+ .mpo_sysvsem_create = stub_sysvsem_create,
+ .mpo_sysvsem_destroy_label = stub_destroy_label,
+ .mpo_sysvsem_init_label = stub_init_label,
+
+ .mpo_sysvshm_check_shmat = stub_sysvshm_check_shmat,
+ .mpo_sysvshm_check_shmctl = stub_sysvshm_check_shmctl,
+ .mpo_sysvshm_check_shmdt = stub_sysvshm_check_shmdt,
+ .mpo_sysvshm_check_shmget = stub_sysvshm_check_shmget,
+ .mpo_sysvshm_cleanup = stub_sysvshm_cleanup,
+ .mpo_sysvshm_create = stub_sysvshm_create,
+ .mpo_sysvshm_destroy_label = stub_destroy_label,
+ .mpo_sysvshm_init_label = stub_init_label,
+
+ .mpo_system_check_acct = stub_system_check_acct,
+ .mpo_system_check_audit = stub_system_check_audit,
+ .mpo_system_check_auditctl = stub_system_check_auditctl,
+ .mpo_system_check_auditon = stub_system_check_auditon,
+ .mpo_system_check_reboot = stub_system_check_reboot,
+ .mpo_system_check_swapoff = stub_system_check_swapoff,
+ .mpo_system_check_swapon = stub_system_check_swapon,
+ .mpo_system_check_sysctl = stub_system_check_sysctl,
+
+ .mpo_thread_userret = stub_thread_userret,
+
+ .mpo_vnode_associate_extattr = stub_vnode_associate_extattr,
+ .mpo_vnode_associate_singlelabel = stub_vnode_associate_singlelabel,
+ .mpo_vnode_check_access = stub_vnode_check_access,
+ .mpo_vnode_check_chdir = stub_vnode_check_chdir,
+ .mpo_vnode_check_chroot = stub_vnode_check_chroot,
+ .mpo_vnode_check_create = stub_vnode_check_create,
+ .mpo_vnode_check_deleteacl = stub_vnode_check_deleteacl,
+ .mpo_vnode_check_deleteextattr = stub_vnode_check_deleteextattr,
+ .mpo_vnode_check_exec = stub_vnode_check_exec,
+ .mpo_vnode_check_getacl = stub_vnode_check_getacl,
+ .mpo_vnode_check_getextattr = stub_vnode_check_getextattr,
+ .mpo_vnode_check_link = stub_vnode_check_link,
+ .mpo_vnode_check_listextattr = stub_vnode_check_listextattr,
+ .mpo_vnode_check_lookup = stub_vnode_check_lookup,
+ .mpo_vnode_check_mmap = stub_vnode_check_mmap,
+ .mpo_vnode_check_mmap_downgrade = stub_vnode_check_mmap_downgrade,
+ .mpo_vnode_check_mprotect = stub_vnode_check_mprotect,
+ .mpo_vnode_check_open = stub_vnode_check_open,
+ .mpo_vnode_check_poll = stub_vnode_check_poll,
+ .mpo_vnode_check_read = stub_vnode_check_read,
+ .mpo_vnode_check_readdir = stub_vnode_check_readdir,
+ .mpo_vnode_check_readlink = stub_vnode_check_readlink,
+ .mpo_vnode_check_relabel = stub_vnode_check_relabel,
+ .mpo_vnode_check_rename_from = stub_vnode_check_rename_from,
+ .mpo_vnode_check_rename_to = stub_vnode_check_rename_to,
+ .mpo_vnode_check_revoke = stub_vnode_check_revoke,
+ .mpo_vnode_check_setacl = stub_vnode_check_setacl,
+ .mpo_vnode_check_setextattr = stub_vnode_check_setextattr,
+ .mpo_vnode_check_setflags = stub_vnode_check_setflags,
+ .mpo_vnode_check_setmode = stub_vnode_check_setmode,
+ .mpo_vnode_check_setowner = stub_vnode_check_setowner,
+ .mpo_vnode_check_setutimes = stub_vnode_check_setutimes,
+ .mpo_vnode_check_stat = stub_vnode_check_stat,
+ .mpo_vnode_check_unlink = stub_vnode_check_unlink,
+ .mpo_vnode_check_write = stub_vnode_check_write,
+ .mpo_vnode_copy_label = stub_copy_label,
+ .mpo_vnode_create_extattr = stub_vnode_create_extattr,
+ .mpo_vnode_destroy_label = stub_destroy_label,
+ .mpo_vnode_execve_transition = stub_vnode_execve_transition,
+ .mpo_vnode_execve_will_transition = stub_vnode_execve_will_transition,
+ .mpo_vnode_externalize_label = stub_externalize_label,
+ .mpo_vnode_init_label = stub_init_label,
+ .mpo_vnode_internalize_label = stub_internalize_label,
+ .mpo_vnode_relabel = stub_vnode_relabel,
+ .mpo_vnode_setlabel_extattr = stub_vnode_setlabel_extattr,
+};
+
+#define STUB_OBJECTS (MPC_OBJECT_CRED | \
+ /* XXX: MPC_OBJECT_PROC | */ \
+ MPC_OBJECT_VNODE | \
+ MPC_OBJECT_INPCB | \
+ MPC_OBJECT_SOCKET | \
+ MPC_OBJECT_DEVFS | \
+ MPC_OBJECT_MBUF | \
+ MPC_OBJECT_IPQ | \
+ MPC_OBJECT_IFNET | \
+ MPC_OBJECT_BPFDESC | \
+ MPC_OBJECT_PIPE | \
+ MPC_OBJECT_MOUNT | \
+ MPC_OBJECT_POSIXSEM | \
+ MPC_OBJECT_POSIXSHM | \
+ MPC_OBJECT_SYSVMSG | \
+ MPC_OBJECT_SYSVMSQ | \
+ MPC_OBJECT_SYSVSEM | \
+ MPC_OBJECT_SYSVSHM | \
+ MPC_OBJECT_SYNCACHE)
+
+MAC_POLICY_SET(&stub_ops, mac_stub, "TrustedBSD MAC/Stub",
+ MPC_LOADTIME_FLAG_UNLOADOK, NULL, STUB_OBJECTS);
diff --git a/sys/security/mac_test/mac_test.c b/sys/security/mac_test/mac_test.c
new file mode 100644
index 0000000..08f8dd8
--- /dev/null
+++ b/sys/security/mac_test/mac_test.c
@@ -0,0 +1,3163 @@
+/*-
+ * Copyright (c) 1999-2002, 2007-2008 Robert N. M. Watson
+ * Copyright (c) 2001-2005 McAfee, Inc.
+ * Copyright (c) 2006 SPARTA, Inc.
+ * Copyright (c) 2008 Apple Inc.
+ * All rights reserved.
+ *
+ * This software was developed by Robert Watson for the TrustedBSD Project.
+ *
+ * This software was developed for the FreeBSD Project in part by McAfee
+ * Research, the Security Research Division of McAfee, Inc. under
+ * DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA
+ * CHATS research program.
+ *
+ * This software was enhanced by SPARTA ISSO under SPAWAR contract
+ * N66001-04-C-6019 ("SEFOS").
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Developed by the TrustedBSD Project.
+ *
+ * MAC Test policy - tests MAC Framework labeling by assigning object class
+ * magic numbers to each label and validates that each time an object label
+ * is passed into the policy, it has a consistent object type, catching
+ * incorrectly passed labels, labels passed after free, etc.
+ */
+
+#include <sys/param.h>
+#include <sys/acl.h>
+#include <sys/kdb.h>
+#include <sys/kernel.h>
+#include <sys/ksem.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/mount.h>
+#include <sys/msg.h>
+#include <sys/proc.h>
+#include <sys/vnode.h>
+#include <sys/sem.h>
+#include <sys/shm.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/sx.h>
+#include <sys/sysctl.h>
+
+#include <fs/devfs/devfs.h>
+
+#include <net/bpfdesc.h>
+#include <net/if.h>
+#include <net/if_types.h>
+#include <net/if_var.h>
+
+#include <security/mac/mac_policy.h>
+
+SYSCTL_DECL(_security_mac);
+
+SYSCTL_NODE(_security_mac, OID_AUTO, test, CTLFLAG_RW, 0,
+ "TrustedBSD mac_test policy controls");
+
+#define MAGIC_BPF 0xfe1ad1b6
+#define MAGIC_DEVFS 0x9ee79c32
+#define MAGIC_IFNET 0xc218b120
+#define MAGIC_INPCB 0x4440f7bb
+#define MAGIC_IP6Q 0x0870e1b7
+#define MAGIC_IPQ 0x206188ef
+#define MAGIC_MBUF 0xbbefa5bb
+#define MAGIC_MOUNT 0xc7c46e47
+#define MAGIC_SOCKET 0x9199c6cd
+#define MAGIC_SYNCACHE 0x7fb838a8
+#define MAGIC_SYSV_MSG 0x8bbba61e
+#define MAGIC_SYSV_MSQ 0xea672391
+#define MAGIC_SYSV_SEM 0x896e8a0b
+#define MAGIC_SYSV_SHM 0x76119ab0
+#define MAGIC_PIPE 0xdc6c9919
+#define MAGIC_POSIX_SEM 0x78ae980c
+#define MAGIC_POSIX_SHM 0x4e853fc9
+#define MAGIC_PROC 0x3b4be98f
+#define MAGIC_CRED 0x9a5a4987
+#define MAGIC_VNODE 0x1a67a45c
+#define MAGIC_FREE 0x849ba1fd
+
+#define SLOT(x) mac_label_get((x), test_slot)
+#define SLOT_SET(x, v) mac_label_set((x), test_slot, (v))
+
+static int test_slot;
+SYSCTL_INT(_security_mac_test, OID_AUTO, slot, CTLFLAG_RD,
+ &test_slot, 0, "Slot allocated by framework");
+
+SYSCTL_NODE(_security_mac_test, OID_AUTO, counter, CTLFLAG_RW, 0,
+ "TrustedBSD mac_test counters controls");
+
+#define COUNTER_DECL(variable) \
+ static int counter_##variable; \
+ SYSCTL_INT(_security_mac_test_counter, OID_AUTO, variable, \
+ CTLFLAG_RD, &counter_##variable, 0, #variable)
+
+#define COUNTER_INC(variable) atomic_add_int(&counter_##variable, 1)
+
+#ifdef KDB
+#define DEBUGGER(func, string) kdb_enter(KDB_WHY_MAC, (string))
+#else
+#define DEBUGGER(func, string) printf("mac_test: %s: %s\n", (func), (string))
+#endif
+
+#define LABEL_CHECK(label, magic) do { \
+ if (label != NULL) { \
+ KASSERT(SLOT(label) == magic || SLOT(label) == 0, \
+ ("%s: bad %s label", __func__, #magic)); \
+ } \
+} while (0)
+
+#define LABEL_DESTROY(label, magic) do { \
+ if (SLOT(label) == magic || SLOT(label) == 0) { \
+ SLOT_SET(label, MAGIC_FREE); \
+ } else if (SLOT(label) == MAGIC_FREE) { \
+ DEBUGGER("%s: dup destroy", __func__); \
+ } else { \
+ DEBUGGER("%s: corrupted label", __func__); \
+ } \
+} while (0)
+
+#define LABEL_INIT(label, magic) do { \
+ SLOT_SET(label, magic); \
+} while (0)
+
+#define LABEL_NOTFREE(label) do { \
+ KASSERT(SLOT(label) != MAGIC_FREE, \
+ ("%s: destroyed label", __func__)); \
+} while (0)
+
+/*
+ * Object-specific entry point implementations are sorted alphabetically by
+ * object type name and then by operation.
+ */
+COUNTER_DECL(bpfdesc_check_receive);
+static int
+test_bpfdesc_check_receive(struct bpf_d *d, struct label *dlabel,
+ struct ifnet *ifp, struct label *ifplabel)
+{
+
+ LABEL_CHECK(dlabel, MAGIC_BPF);
+ LABEL_CHECK(ifplabel, MAGIC_IFNET);
+ COUNTER_INC(bpfdesc_check_receive);
+
+ return (0);
+}
+
+COUNTER_DECL(bpfdesc_create);
+static void
+test_bpfdesc_create(struct ucred *cred, struct bpf_d *d,
+ struct label *dlabel)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(dlabel, MAGIC_BPF);
+ COUNTER_INC(bpfdesc_create);
+}
+
+COUNTER_DECL(bpfdesc_create_mbuf);
+static void
+test_bpfdesc_create_mbuf(struct bpf_d *d, struct label *dlabel,
+ struct mbuf *m, struct label *mlabel)
+{
+
+ LABEL_CHECK(dlabel, MAGIC_BPF);
+ LABEL_CHECK(mlabel, MAGIC_MBUF);
+ COUNTER_INC(bpfdesc_create_mbuf);
+}
+
+COUNTER_DECL(bpfdesc_destroy_label);
+static void
+test_bpfdesc_destroy_label(struct label *label)
+{
+
+ LABEL_DESTROY(label, MAGIC_BPF);
+ COUNTER_INC(bpfdesc_destroy_label);
+}
+
+COUNTER_DECL(bpfdesc_init_label);
+static void
+test_bpfdesc_init_label(struct label *label)
+{
+
+ LABEL_INIT(label, MAGIC_BPF);
+ COUNTER_INC(bpfdesc_init_label);
+}
+
+COUNTER_DECL(cred_check_relabel);
+static int
+test_cred_check_relabel(struct ucred *cred, struct label *newlabel)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(newlabel, MAGIC_CRED);
+ COUNTER_INC(cred_check_relabel);
+
+ return (0);
+}
+
+COUNTER_DECL(cred_check_visible);
+static int
+test_cred_check_visible(struct ucred *u1, struct ucred *u2)
+{
+
+ LABEL_CHECK(u1->cr_label, MAGIC_CRED);
+ LABEL_CHECK(u2->cr_label, MAGIC_CRED);
+ COUNTER_INC(cred_check_visible);
+
+ return (0);
+}
+
+COUNTER_DECL(cred_copy_label);
+static void
+test_cred_copy_label(struct label *src, struct label *dest)
+{
+
+ LABEL_CHECK(src, MAGIC_CRED);
+ LABEL_CHECK(dest, MAGIC_CRED);
+ COUNTER_INC(cred_copy_label);
+}
+
+COUNTER_DECL(cred_create_init);
+static void
+test_cred_create_init(struct ucred *cred)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ COUNTER_INC(cred_create_init);
+}
+
+COUNTER_DECL(cred_create_swapper);
+static void
+test_cred_create_swapper(struct ucred *cred)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ COUNTER_INC(cred_create_swapper);
+}
+
+COUNTER_DECL(cred_destroy_label);
+static void
+test_cred_destroy_label(struct label *label)
+{
+
+ LABEL_DESTROY(label, MAGIC_CRED);
+ COUNTER_INC(cred_destroy_label);
+}
+
+COUNTER_DECL(cred_externalize_label);
+static int
+test_cred_externalize_label(struct label *label, char *element_name,
+ struct sbuf *sb, int *claimed)
+{
+
+ LABEL_CHECK(label, MAGIC_CRED);
+ COUNTER_INC(cred_externalize_label);
+
+ return (0);
+}
+
+COUNTER_DECL(cred_init_label);
+static void
+test_cred_init_label(struct label *label)
+{
+
+ LABEL_INIT(label, MAGIC_CRED);
+ COUNTER_INC(cred_init_label);
+}
+
+COUNTER_DECL(cred_internalize_label);
+static int
+test_cred_internalize_label(struct label *label, char *element_name,
+ char *element_data, int *claimed)
+{
+
+ LABEL_CHECK(label, MAGIC_CRED);
+ COUNTER_INC(cred_internalize_label);
+
+ return (0);
+}
+
+COUNTER_DECL(cred_relabel);
+static void
+test_cred_relabel(struct ucred *cred, struct label *newlabel)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(newlabel, MAGIC_CRED);
+ COUNTER_INC(cred_relabel);
+}
+
+COUNTER_DECL(devfs_create_device);
+static void
+test_devfs_create_device(struct ucred *cred, struct mount *mp,
+ struct cdev *dev, struct devfs_dirent *de, struct label *delabel)
+{
+
+ if (cred != NULL)
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(delabel, MAGIC_DEVFS);
+ COUNTER_INC(devfs_create_device);
+}
+
+COUNTER_DECL(devfs_create_directory);
+static void
+test_devfs_create_directory(struct mount *mp, char *dirname,
+ int dirnamelen, struct devfs_dirent *de, struct label *delabel)
+{
+
+ LABEL_CHECK(delabel, MAGIC_DEVFS);
+ COUNTER_INC(devfs_create_directory);
+}
+
+COUNTER_DECL(devfs_create_symlink);
+static void
+test_devfs_create_symlink(struct ucred *cred, struct mount *mp,
+ struct devfs_dirent *dd, struct label *ddlabel, struct devfs_dirent *de,
+ struct label *delabel)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(ddlabel, MAGIC_DEVFS);
+ LABEL_CHECK(delabel, MAGIC_DEVFS);
+ COUNTER_INC(devfs_create_symlink);
+}
+
+COUNTER_DECL(devfs_destroy_label);
+static void
+test_devfs_destroy_label(struct label *label)
+{
+
+ LABEL_DESTROY(label, MAGIC_DEVFS);
+ COUNTER_INC(devfs_destroy_label);
+}
+
+COUNTER_DECL(devfs_init_label);
+static void
+test_devfs_init_label(struct label *label)
+{
+
+ LABEL_INIT(label, MAGIC_DEVFS);
+ COUNTER_INC(devfs_init_label);
+}
+
+COUNTER_DECL(devfs_update);
+static void
+test_devfs_update(struct mount *mp, struct devfs_dirent *devfs_dirent,
+ struct label *direntlabel, struct vnode *vp, struct label *vplabel)
+{
+
+ LABEL_CHECK(direntlabel, MAGIC_DEVFS);
+ LABEL_CHECK(vplabel, MAGIC_VNODE);
+ COUNTER_INC(devfs_update);
+}
+
+COUNTER_DECL(devfs_vnode_associate);
+static void
+test_devfs_vnode_associate(struct mount *mp, struct label *mplabel,
+ struct devfs_dirent *de, struct label *delabel, struct vnode *vp,
+ struct label *vplabel)
+{
+
+ LABEL_CHECK(mplabel, MAGIC_MOUNT);
+ LABEL_CHECK(delabel, MAGIC_DEVFS);
+ LABEL_CHECK(vplabel, MAGIC_VNODE);
+ COUNTER_INC(devfs_vnode_associate);
+}
+
+COUNTER_DECL(ifnet_check_relabel);
+static int
+test_ifnet_check_relabel(struct ucred *cred, struct ifnet *ifp,
+ struct label *ifplabel, struct label *newlabel)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(ifplabel, MAGIC_IFNET);
+ LABEL_CHECK(newlabel, MAGIC_IFNET);
+ COUNTER_INC(ifnet_check_relabel);
+
+ return (0);
+}
+
+COUNTER_DECL(ifnet_check_transmit);
+static int
+test_ifnet_check_transmit(struct ifnet *ifp, struct label *ifplabel,
+ struct mbuf *m, struct label *mlabel)
+{
+
+ LABEL_CHECK(ifplabel, MAGIC_IFNET);
+ LABEL_CHECK(mlabel, MAGIC_MBUF);
+ COUNTER_INC(ifnet_check_transmit);
+
+ return (0);
+}
+
+COUNTER_DECL(ifnet_copy_label);
+static void
+test_ifnet_copy_label(struct label *src, struct label *dest)
+{
+
+ LABEL_CHECK(src, MAGIC_IFNET);
+ LABEL_CHECK(dest, MAGIC_IFNET);
+ COUNTER_INC(ifnet_copy_label);
+}
+
+COUNTER_DECL(ifnet_create);
+static void
+test_ifnet_create(struct ifnet *ifp, struct label *ifplabel)
+{
+
+ LABEL_CHECK(ifplabel, MAGIC_IFNET);
+ COUNTER_INC(ifnet_create);
+}
+
+COUNTER_DECL(ifnet_create_mbuf);
+static void
+test_ifnet_create_mbuf(struct ifnet *ifp, struct label *ifplabel,
+ struct mbuf *m, struct label *mlabel)
+{
+
+ LABEL_CHECK(ifplabel, MAGIC_IFNET);
+ LABEL_CHECK(mlabel, MAGIC_MBUF);
+ COUNTER_INC(ifnet_create_mbuf);
+}
+
+COUNTER_DECL(ifnet_destroy_label);
+static void
+test_ifnet_destroy_label(struct label *label)
+{
+
+ LABEL_DESTROY(label, MAGIC_IFNET);
+ COUNTER_INC(ifnet_destroy_label);
+}
+
+COUNTER_DECL(ifnet_externalize_label);
+static int
+test_ifnet_externalize_label(struct label *label, char *element_name,
+ struct sbuf *sb, int *claimed)
+{
+
+ LABEL_CHECK(label, MAGIC_IFNET);
+ COUNTER_INC(ifnet_externalize_label);
+
+ return (0);
+}
+
+COUNTER_DECL(ifnet_init_label);
+static void
+test_ifnet_init_label(struct label *label)
+{
+
+ LABEL_INIT(label, MAGIC_IFNET);
+ COUNTER_INC(ifnet_init_label);
+}
+
+COUNTER_DECL(ifnet_internalize_label);
+static int
+test_ifnet_internalize_label(struct label *label, char *element_name,
+ char *element_data, int *claimed)
+{
+
+ LABEL_CHECK(label, MAGIC_IFNET);
+ COUNTER_INC(ifnet_internalize_label);
+
+ return (0);
+}
+
+COUNTER_DECL(ifnet_relabel);
+static void
+test_ifnet_relabel(struct ucred *cred, struct ifnet *ifp,
+ struct label *ifplabel, struct label *newlabel)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(ifplabel, MAGIC_IFNET);
+ LABEL_CHECK(newlabel, MAGIC_IFNET);
+ COUNTER_INC(ifnet_relabel);
+}
+
+COUNTER_DECL(inpcb_check_deliver);
+static int
+test_inpcb_check_deliver(struct inpcb *inp, struct label *inplabel,
+ struct mbuf *m, struct label *mlabel)
+{
+
+ LABEL_CHECK(inplabel, MAGIC_INPCB);
+ LABEL_CHECK(mlabel, MAGIC_MBUF);
+ COUNTER_INC(inpcb_check_deliver);
+
+ return (0);
+}
+
+COUNTER_DECL(inpcb_check_visible);
+static int
+test_inpcb_check_visible(struct ucred *cred, struct inpcb *inp,
+ struct label *inplabel)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(inplabel, MAGIC_INPCB);
+ COUNTER_INC(inpcb_check_visible);
+
+ return (0);
+}
+
+COUNTER_DECL(inpcb_create);
+static void
+test_inpcb_create(struct socket *so, struct label *solabel,
+ struct inpcb *inp, struct label *inplabel)
+{
+
+ LABEL_CHECK(solabel, MAGIC_SOCKET);
+ LABEL_CHECK(inplabel, MAGIC_INPCB);
+ COUNTER_INC(inpcb_create);
+}
+
+COUNTER_DECL(inpcb_create_mbuf);
+static void
+test_inpcb_create_mbuf(struct inpcb *inp, struct label *inplabel,
+ struct mbuf *m, struct label *mlabel)
+{
+
+ LABEL_CHECK(inplabel, MAGIC_INPCB);
+ LABEL_CHECK(mlabel, MAGIC_MBUF);
+ COUNTER_INC(inpcb_create_mbuf);
+}
+
+COUNTER_DECL(inpcb_destroy_label);
+static void
+test_inpcb_destroy_label(struct label *label)
+{
+
+ LABEL_DESTROY(label, MAGIC_INPCB);
+ COUNTER_INC(inpcb_destroy_label);
+}
+
+COUNTER_DECL(inpcb_init_label);
+static int
+test_inpcb_init_label(struct label *label, int flag)
+{
+
+ if (flag & M_WAITOK)
+ WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL,
+ "test_inpcb_init_label() at %s:%d", __FILE__,
+ __LINE__);
+
+ LABEL_INIT(label, MAGIC_INPCB);
+ COUNTER_INC(inpcb_init_label);
+ return (0);
+}
+
+COUNTER_DECL(inpcb_sosetlabel);
+static void
+test_inpcb_sosetlabel(struct socket *so, struct label *solabel,
+ struct inpcb *inp, struct label *inplabel)
+{
+
+ LABEL_CHECK(solabel, MAGIC_SOCKET);
+ LABEL_CHECK(inplabel, MAGIC_INPCB);
+ COUNTER_INC(inpcb_sosetlabel);
+}
+
+COUNTER_DECL(ip6q_create);
+static void
+test_ip6q_create(struct mbuf *fragment, struct label *fragmentlabel,
+ struct ip6q *q6, struct label *q6label)
+{
+
+ LABEL_CHECK(fragmentlabel, MAGIC_MBUF);
+ LABEL_CHECK(q6label, MAGIC_IP6Q);
+ COUNTER_INC(ip6q_create);
+}
+
+COUNTER_DECL(ip6q_destroy_label);
+static void
+test_ip6q_destroy_label(struct label *label)
+{
+
+ LABEL_DESTROY(label, MAGIC_IP6Q);
+ COUNTER_INC(ip6q_destroy_label);
+}
+
+COUNTER_DECL(ip6q_init_label);
+static int
+test_ip6q_init_label(struct label *label, int flag)
+{
+
+ if (flag & M_WAITOK)
+ WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL,
+ "test_ip6q_init_label() at %s:%d", __FILE__,
+ __LINE__);
+
+ LABEL_INIT(label, MAGIC_IP6Q);
+ COUNTER_INC(ip6q_init_label);
+ return (0);
+}
+
+COUNTER_DECL(ip6q_match);
+static int
+test_ip6q_match(struct mbuf *fragment, struct label *fragmentlabel,
+ struct ip6q *q6, struct label *q6label)
+{
+
+ LABEL_CHECK(fragmentlabel, MAGIC_MBUF);
+ LABEL_CHECK(q6label, MAGIC_IP6Q);
+ COUNTER_INC(ip6q_match);
+
+ return (1);
+}
+
+COUNTER_DECL(ip6q_reassemble);
+static void
+test_ip6q_reassemble(struct ip6q *q6, struct label *q6label, struct mbuf *m,
+ struct label *mlabel)
+{
+
+ LABEL_CHECK(q6label, MAGIC_IP6Q);
+ LABEL_CHECK(mlabel, MAGIC_MBUF);
+ COUNTER_INC(ip6q_reassemble);
+}
+
+COUNTER_DECL(ip6q_update);
+static void
+test_ip6q_update(struct mbuf *m, struct label *mlabel, struct ip6q *q6,
+ struct label *q6label)
+{
+
+ LABEL_CHECK(mlabel, MAGIC_MBUF);
+ LABEL_CHECK(q6label, MAGIC_IP6Q);
+ COUNTER_INC(ip6q_update);
+}
+
+COUNTER_DECL(ipq_create);
+static void
+test_ipq_create(struct mbuf *fragment, struct label *fragmentlabel,
+ struct ipq *q, struct label *qlabel)
+{
+
+ LABEL_CHECK(fragmentlabel, MAGIC_MBUF);
+ LABEL_CHECK(qlabel, MAGIC_IPQ);
+ COUNTER_INC(ipq_create);
+}
+
+COUNTER_DECL(ipq_destroy_label);
+static void
+test_ipq_destroy_label(struct label *label)
+{
+
+ LABEL_DESTROY(label, MAGIC_IPQ);
+ COUNTER_INC(ipq_destroy_label);
+}
+
+COUNTER_DECL(ipq_init_label);
+static int
+test_ipq_init_label(struct label *label, int flag)
+{
+
+ if (flag & M_WAITOK)
+ WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL,
+ "test_ipq_init_label() at %s:%d", __FILE__,
+ __LINE__);
+
+ LABEL_INIT(label, MAGIC_IPQ);
+ COUNTER_INC(ipq_init_label);
+ return (0);
+}
+
+COUNTER_DECL(ipq_match);
+static int
+test_ipq_match(struct mbuf *fragment, struct label *fragmentlabel,
+ struct ipq *q, struct label *qlabel)
+{
+
+ LABEL_CHECK(fragmentlabel, MAGIC_MBUF);
+ LABEL_CHECK(qlabel, MAGIC_IPQ);
+ COUNTER_INC(ipq_match);
+
+ return (1);
+}
+
+COUNTER_DECL(ipq_reassemble);
+static void
+test_ipq_reassemble(struct ipq *q, struct label *qlabel, struct mbuf *m,
+ struct label *mlabel)
+{
+
+ LABEL_CHECK(qlabel, MAGIC_IPQ);
+ LABEL_CHECK(mlabel, MAGIC_MBUF);
+ COUNTER_INC(ipq_reassemble);
+}
+
+COUNTER_DECL(ipq_update);
+static void
+test_ipq_update(struct mbuf *m, struct label *mlabel, struct ipq *q,
+ struct label *qlabel)
+{
+
+ LABEL_CHECK(mlabel, MAGIC_MBUF);
+ LABEL_CHECK(qlabel, MAGIC_IPQ);
+ COUNTER_INC(ipq_update);
+}
+
+COUNTER_DECL(kenv_check_dump);
+static int
+test_kenv_check_dump(struct ucred *cred)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ COUNTER_INC(kenv_check_dump);
+
+ return (0);
+}
+
+COUNTER_DECL(kenv_check_get);
+static int
+test_kenv_check_get(struct ucred *cred, char *name)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ COUNTER_INC(kenv_check_get);
+
+ return (0);
+}
+
+COUNTER_DECL(kenv_check_set);
+static int
+test_kenv_check_set(struct ucred *cred, char *name, char *value)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ COUNTER_INC(kenv_check_set);
+
+ return (0);
+}
+
+COUNTER_DECL(kenv_check_unset);
+static int
+test_kenv_check_unset(struct ucred *cred, char *name)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ COUNTER_INC(kenv_check_unset);
+
+ return (0);
+}
+
+COUNTER_DECL(kld_check_load);
+static int
+test_kld_check_load(struct ucred *cred, struct vnode *vp,
+ struct label *label)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(label, MAGIC_VNODE);
+ COUNTER_INC(kld_check_load);
+
+ return (0);
+}
+
+COUNTER_DECL(kld_check_stat);
+static int
+test_kld_check_stat(struct ucred *cred)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ COUNTER_INC(kld_check_stat);
+
+ return (0);
+}
+
+COUNTER_DECL(mbuf_copy_label);
+static void
+test_mbuf_copy_label(struct label *src, struct label *dest)
+{
+
+ LABEL_CHECK(src, MAGIC_MBUF);
+ LABEL_CHECK(dest, MAGIC_MBUF);
+ COUNTER_INC(mbuf_copy_label);
+}
+
+COUNTER_DECL(mbuf_destroy_label);
+static void
+test_mbuf_destroy_label(struct label *label)
+{
+
+ /*
+ * If we're loaded dynamically, there may be mbufs in flight that
+ * didn't have label storage allocated for them. Handle this
+ * gracefully.
+ */
+ if (label == NULL)
+ return;
+
+ LABEL_DESTROY(label, MAGIC_MBUF);
+ COUNTER_INC(mbuf_destroy_label);
+}
+
+COUNTER_DECL(mbuf_init_label);
+static int
+test_mbuf_init_label(struct label *label, int flag)
+{
+
+ if (flag & M_WAITOK)
+ WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL,
+ "test_mbuf_init_label() at %s:%d", __FILE__,
+ __LINE__);
+
+ LABEL_INIT(label, MAGIC_MBUF);
+ COUNTER_INC(mbuf_init_label);
+ return (0);
+}
+
+COUNTER_DECL(mount_check_stat);
+static int
+test_mount_check_stat(struct ucred *cred, struct mount *mp,
+ struct label *mplabel)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(mplabel, MAGIC_MOUNT);
+ COUNTER_INC(mount_check_stat);
+
+ return (0);
+}
+
+COUNTER_DECL(mount_create);
+static void
+test_mount_create(struct ucred *cred, struct mount *mp,
+ struct label *mplabel)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(mplabel, MAGIC_MOUNT);
+ COUNTER_INC(mount_create);
+}
+
+COUNTER_DECL(mount_destroy_label);
+static void
+test_mount_destroy_label(struct label *label)
+{
+
+ LABEL_DESTROY(label, MAGIC_MOUNT);
+ COUNTER_INC(mount_destroy_label);
+}
+
+COUNTER_DECL(mount_init_label);
+static void
+test_mount_init_label(struct label *label)
+{
+
+ LABEL_INIT(label, MAGIC_MOUNT);
+ COUNTER_INC(mount_init_label);
+}
+
+COUNTER_DECL(netatalk_aarp_send);
+static void
+test_netatalk_aarp_send(struct ifnet *ifp, struct label *ifplabel,
+ struct mbuf *m, struct label *mlabel)
+{
+
+ LABEL_CHECK(ifplabel, MAGIC_IFNET);
+ LABEL_CHECK(mlabel, MAGIC_MBUF);
+ COUNTER_INC(netatalk_aarp_send);
+}
+
+COUNTER_DECL(netinet_arp_send);
+static void
+test_netinet_arp_send(struct ifnet *ifp, struct label *ifplabel,
+ struct mbuf *m, struct label *mlabel)
+{
+
+ LABEL_CHECK(ifplabel, MAGIC_IFNET);
+ LABEL_CHECK(mlabel, MAGIC_MBUF);
+ COUNTER_INC(netinet_arp_send);
+}
+
+COUNTER_DECL(netinet_fragment);
+static void
+test_netinet_fragment(struct mbuf *m, struct label *mlabel,
+ struct mbuf *frag, struct label *fraglabel)
+{
+
+ LABEL_CHECK(mlabel, MAGIC_MBUF);
+ LABEL_CHECK(fraglabel, MAGIC_MBUF);
+ COUNTER_INC(netinet_fragment);
+}
+
+COUNTER_DECL(netinet_icmp_reply);
+static void
+test_netinet_icmp_reply(struct mbuf *mrecv, struct label *mrecvlabel,
+ struct mbuf *msend, struct label *msendlabel)
+{
+
+ LABEL_CHECK(mrecvlabel, MAGIC_MBUF);
+ LABEL_CHECK(msendlabel, MAGIC_MBUF);
+ COUNTER_INC(netinet_icmp_reply);
+}
+
+COUNTER_DECL(netinet_icmp_replyinplace);
+static void
+test_netinet_icmp_replyinplace(struct mbuf *m, struct label *mlabel)
+{
+
+ LABEL_CHECK(mlabel, MAGIC_MBUF);
+ COUNTER_INC(netinet_icmp_replyinplace);
+}
+
+COUNTER_DECL(netinet_igmp_send);
+static void
+test_netinet_igmp_send(struct ifnet *ifp, struct label *ifplabel,
+ struct mbuf *m, struct label *mlabel)
+{
+
+ LABEL_CHECK(ifplabel, MAGIC_IFNET);
+ LABEL_CHECK(mlabel, MAGIC_MBUF);
+ COUNTER_INC(netinet_igmp_send);
+}
+
+COUNTER_DECL(netinet_tcp_reply);
+static void
+test_netinet_tcp_reply(struct mbuf *m, struct label *mlabel)
+{
+
+ LABEL_CHECK(mlabel, MAGIC_MBUF);
+ COUNTER_INC(netinet_tcp_reply);
+}
+
+COUNTER_DECL(netinet6_nd6_send);
+static void
+test_netinet6_nd6_send(struct ifnet *ifp, struct label *ifplabel,
+ struct mbuf *m, struct label *mlabel)
+{
+
+ LABEL_CHECK(ifplabel, MAGIC_IFNET);
+ LABEL_CHECK(mlabel, MAGIC_MBUF);
+ COUNTER_INC(netinet6_nd6_send);
+}
+
+COUNTER_DECL(pipe_check_ioctl);
+static int
+test_pipe_check_ioctl(struct ucred *cred, struct pipepair *pp,
+ struct label *pplabel, unsigned long cmd, void /* caddr_t */ *data)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(pplabel, MAGIC_PIPE);
+ COUNTER_INC(pipe_check_ioctl);
+
+ return (0);
+}
+
+COUNTER_DECL(pipe_check_poll);
+static int
+test_pipe_check_poll(struct ucred *cred, struct pipepair *pp,
+ struct label *pplabel)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(pplabel, MAGIC_PIPE);
+ COUNTER_INC(pipe_check_poll);
+
+ return (0);
+}
+
+COUNTER_DECL(pipe_check_read);
+static int
+test_pipe_check_read(struct ucred *cred, struct pipepair *pp,
+ struct label *pplabel)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(pplabel, MAGIC_PIPE);
+ COUNTER_INC(pipe_check_read);
+
+ return (0);
+}
+
+COUNTER_DECL(pipe_check_relabel);
+static int
+test_pipe_check_relabel(struct ucred *cred, struct pipepair *pp,
+ struct label *pplabel, struct label *newlabel)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(pplabel, MAGIC_PIPE);
+ LABEL_CHECK(newlabel, MAGIC_PIPE);
+ COUNTER_INC(pipe_check_relabel);
+
+ return (0);
+}
+
+COUNTER_DECL(pipe_check_stat);
+static int
+test_pipe_check_stat(struct ucred *cred, struct pipepair *pp,
+ struct label *pplabel)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(pplabel, MAGIC_PIPE);
+ COUNTER_INC(pipe_check_stat);
+
+ return (0);
+}
+
+COUNTER_DECL(pipe_check_write);
+static int
+test_pipe_check_write(struct ucred *cred, struct pipepair *pp,
+ struct label *pplabel)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(pplabel, MAGIC_PIPE);
+ COUNTER_INC(pipe_check_write);
+
+ return (0);
+}
+
+COUNTER_DECL(pipe_copy_label);
+static void
+test_pipe_copy_label(struct label *src, struct label *dest)
+{
+
+ LABEL_CHECK(src, MAGIC_PIPE);
+ LABEL_CHECK(dest, MAGIC_PIPE);
+ COUNTER_INC(pipe_copy_label);
+}
+
+COUNTER_DECL(pipe_create);
+static void
+test_pipe_create(struct ucred *cred, struct pipepair *pp,
+ struct label *pplabel)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(pplabel, MAGIC_PIPE);
+ COUNTER_INC(pipe_create);
+}
+
+COUNTER_DECL(pipe_destroy_label);
+static void
+test_pipe_destroy_label(struct label *label)
+{
+
+ LABEL_DESTROY(label, MAGIC_PIPE);
+ COUNTER_INC(pipe_destroy_label);
+}
+
+COUNTER_DECL(pipe_externalize_label);
+static int
+test_pipe_externalize_label(struct label *label, char *element_name,
+ struct sbuf *sb, int *claimed)
+{
+
+ LABEL_CHECK(label, MAGIC_PIPE);
+ COUNTER_INC(pipe_externalize_label);
+
+ return (0);
+}
+
+COUNTER_DECL(pipe_init_label);
+static void
+test_pipe_init_label(struct label *label)
+{
+
+ LABEL_INIT(label, MAGIC_PIPE);
+ COUNTER_INC(pipe_init_label);
+}
+
+COUNTER_DECL(pipe_internalize_label);
+static int
+test_pipe_internalize_label(struct label *label, char *element_name,
+ char *element_data, int *claimed)
+{
+
+ LABEL_CHECK(label, MAGIC_PIPE);
+ COUNTER_INC(pipe_internalize_label);
+
+ return (0);
+}
+
+COUNTER_DECL(pipe_relabel);
+static void
+test_pipe_relabel(struct ucred *cred, struct pipepair *pp,
+ struct label *pplabel, struct label *newlabel)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(pplabel, MAGIC_PIPE);
+ LABEL_CHECK(newlabel, MAGIC_PIPE);
+ COUNTER_INC(pipe_relabel);
+}
+
+COUNTER_DECL(posixsem_check_getvalue);
+static int
+test_posixsem_check_getvalue(struct ucred *active_cred, struct ucred *file_cred,
+ struct ksem *ks, struct label *kslabel)
+{
+
+ LABEL_CHECK(active_cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(file_cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(kslabel, MAGIC_POSIX_SEM);
+ COUNTER_INC(posixsem_check_getvalue);
+
+ return (0);
+}
+
+COUNTER_DECL(posixsem_check_open);
+static int
+test_posixsem_check_open(struct ucred *cred, struct ksem *ks,
+ struct label *kslabel)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(kslabel, MAGIC_POSIX_SEM);
+ COUNTER_INC(posixsem_check_open);
+
+ return (0);
+}
+
+COUNTER_DECL(posixsem_check_post);
+static int
+test_posixsem_check_post(struct ucred *active_cred, struct ucred *file_cred,
+ struct ksem *ks, struct label *kslabel)
+{
+
+ LABEL_CHECK(active_cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(file_cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(kslabel, MAGIC_POSIX_SEM);
+ COUNTER_INC(posixsem_check_post);
+
+ return (0);
+}
+
+COUNTER_DECL(posixsem_check_stat);
+static int
+test_posixsem_check_stat(struct ucred *active_cred,
+ struct ucred *file_cred, struct ksem *ks, struct label *kslabel)
+{
+
+ LABEL_CHECK(active_cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(file_cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(kslabel, MAGIC_POSIX_SEM);
+ COUNTER_INC(posixsem_check_stat);
+ return (0);
+}
+
+COUNTER_DECL(posixsem_check_unlink);
+static int
+test_posixsem_check_unlink(struct ucred *cred, struct ksem *ks,
+ struct label *kslabel)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(kslabel, MAGIC_POSIX_SEM);
+ COUNTER_INC(posixsem_check_unlink);
+
+ return (0);
+}
+
+COUNTER_DECL(posixsem_check_wait);
+static int
+test_posixsem_check_wait(struct ucred *active_cred, struct ucred *file_cred,
+ struct ksem *ks, struct label *kslabel)
+{
+
+ LABEL_CHECK(active_cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(file_cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(kslabel, MAGIC_POSIX_SEM);
+ COUNTER_INC(posixsem_check_wait);
+
+ return (0);
+}
+
+COUNTER_DECL(posixsem_create);
+static void
+test_posixsem_create(struct ucred *cred, struct ksem *ks,
+ struct label *kslabel)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(kslabel, MAGIC_POSIX_SEM);
+ COUNTER_INC(posixsem_create);
+}
+
+COUNTER_DECL(posixsem_destroy_label);
+static void
+test_posixsem_destroy_label(struct label *label)
+{
+
+ LABEL_DESTROY(label, MAGIC_POSIX_SEM);
+ COUNTER_INC(posixsem_destroy_label);
+}
+
+COUNTER_DECL(posixsem_init_label);
+static void
+test_posixsem_init_label(struct label *label)
+{
+
+ LABEL_INIT(label, MAGIC_POSIX_SEM);
+ COUNTER_INC(posixsem_init_label);
+}
+
+COUNTER_DECL(posixshm_check_mmap);
+static int
+test_posixshm_check_mmap(struct ucred *cred, struct shmfd *shmfd,
+ struct label *shmfdlabel, int prot, int flags)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(shmfdlabel, MAGIC_POSIX_SHM);
+ COUNTER_INC(posixshm_check_mmap);
+ return (0);
+}
+
+COUNTER_DECL(posixshm_check_open);
+static int
+test_posixshm_check_open(struct ucred *cred, struct shmfd *shmfd,
+ struct label *shmfdlabel)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(shmfdlabel, MAGIC_POSIX_SHM);
+ COUNTER_INC(posixshm_check_open);
+ return (0);
+}
+
+COUNTER_DECL(posixshm_check_stat);
+static int
+test_posixshm_check_stat(struct ucred *active_cred,
+ struct ucred *file_cred, struct shmfd *shmfd, struct label *shmfdlabel)
+{
+
+ LABEL_CHECK(active_cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(file_cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(shmfdlabel, MAGIC_POSIX_SHM);
+ COUNTER_INC(posixshm_check_stat);
+ return (0);
+}
+
+COUNTER_DECL(posixshm_check_truncate);
+static int
+test_posixshm_check_truncate(struct ucred *active_cred,
+ struct ucred *file_cred, struct shmfd *shmfd, struct label *shmfdlabel)
+{
+
+ LABEL_CHECK(active_cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(file_cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(shmfdlabel, MAGIC_POSIX_SHM);
+ COUNTER_INC(posixshm_check_truncate);
+ return (0);
+}
+
+COUNTER_DECL(posixshm_check_unlink);
+static int
+test_posixshm_check_unlink(struct ucred *cred, struct shmfd *shmfd,
+ struct label *shmfdlabel)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(shmfdlabel, MAGIC_POSIX_SHM);
+ COUNTER_INC(posixshm_check_unlink);
+ return (0);
+}
+
+COUNTER_DECL(posixshm_create);
+static void
+test_posixshm_create(struct ucred *cred, struct shmfd *shmfd,
+ struct label *shmfdlabel)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(shmfdlabel, MAGIC_POSIX_SHM);
+ COUNTER_INC(posixshm_create);
+}
+
+COUNTER_DECL(posixshm_destroy_label);
+static void
+test_posixshm_destroy_label(struct label *label)
+{
+
+ LABEL_DESTROY(label, MAGIC_POSIX_SHM);
+ COUNTER_INC(posixshm_destroy_label);
+}
+
+COUNTER_DECL(posixshm_init_label);
+static void
+test_posixshm_init_label(struct label *label)
+{
+
+ LABEL_INIT(label, MAGIC_POSIX_SHM);
+ COUNTER_INC(posixshm_init_label);
+}
+
+COUNTER_DECL(proc_check_debug);
+static int
+test_proc_check_debug(struct ucred *cred, struct proc *p)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(p->p_ucred->cr_label, MAGIC_CRED);
+ COUNTER_INC(proc_check_debug);
+
+ return (0);
+}
+
+COUNTER_DECL(proc_check_sched);
+static int
+test_proc_check_sched(struct ucred *cred, struct proc *p)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(p->p_ucred->cr_label, MAGIC_CRED);
+ COUNTER_INC(proc_check_sched);
+
+ return (0);
+}
+
+COUNTER_DECL(proc_check_signal);
+static int
+test_proc_check_signal(struct ucred *cred, struct proc *p, int signum)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(p->p_ucred->cr_label, MAGIC_CRED);
+ COUNTER_INC(proc_check_signal);
+
+ return (0);
+}
+
+COUNTER_DECL(proc_check_setaudit);
+static int
+test_proc_check_setaudit(struct ucred *cred, struct auditinfo *ai)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ COUNTER_INC(proc_check_setaudit);
+
+ return (0);
+}
+
+COUNTER_DECL(proc_check_setaudit_addr);
+static int
+test_proc_check_setaudit_addr(struct ucred *cred,
+ struct auditinfo_addr *aia)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ COUNTER_INC(proc_check_setaudit_addr);
+
+ return (0);
+}
+
+COUNTER_DECL(proc_check_setauid);
+static int
+test_proc_check_setauid(struct ucred *cred, uid_t auid)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ COUNTER_INC(proc_check_setauid);
+
+ return (0);
+}
+
+COUNTER_DECL(proc_check_setegid);
+static int
+test_proc_check_setegid(struct ucred *cred, gid_t egid)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ COUNTER_INC(proc_check_setegid);
+
+ return (0);
+}
+
+COUNTER_DECL(proc_check_euid);
+static int
+test_proc_check_seteuid(struct ucred *cred, uid_t euid)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ COUNTER_INC(proc_check_euid);
+
+ return (0);
+}
+
+COUNTER_DECL(proc_check_setregid);
+static int
+test_proc_check_setregid(struct ucred *cred, gid_t rgid, gid_t egid)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ COUNTER_INC(proc_check_setregid);
+
+ return (0);
+}
+
+COUNTER_DECL(proc_check_setreuid);
+static int
+test_proc_check_setreuid(struct ucred *cred, uid_t ruid, uid_t euid)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ COUNTER_INC(proc_check_setreuid);
+
+ return (0);
+}
+
+COUNTER_DECL(proc_check_setgid);
+static int
+test_proc_check_setgid(struct ucred *cred, gid_t gid)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ COUNTER_INC(proc_check_setgid);
+
+ return (0);
+}
+
+COUNTER_DECL(proc_check_setgroups);
+static int
+test_proc_check_setgroups(struct ucred *cred, int ngroups,
+ gid_t *gidset)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ COUNTER_INC(proc_check_setgroups);
+
+ return (0);
+}
+
+COUNTER_DECL(proc_check_setresgid);
+static int
+test_proc_check_setresgid(struct ucred *cred, gid_t rgid, gid_t egid,
+ gid_t sgid)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ COUNTER_INC(proc_check_setresgid);
+
+ return (0);
+}
+
+COUNTER_DECL(proc_check_setresuid);
+static int
+test_proc_check_setresuid(struct ucred *cred, uid_t ruid, uid_t euid,
+ uid_t suid)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ COUNTER_INC(proc_check_setresuid);
+
+ return (0);
+}
+
+COUNTER_DECL(proc_check_setuid);
+static int
+test_proc_check_setuid(struct ucred *cred, uid_t uid)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ COUNTER_INC(proc_check_setuid);
+
+ return (0);
+}
+
+COUNTER_DECL(proc_check_wait);
+static int
+test_proc_check_wait(struct ucred *cred, struct proc *p)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(p->p_ucred->cr_label, MAGIC_CRED);
+ COUNTER_INC(proc_check_wait);
+
+ return (0);
+}
+
+COUNTER_DECL(proc_destroy_label);
+static void
+test_proc_destroy_label(struct label *label)
+{
+
+ LABEL_DESTROY(label, MAGIC_PROC);
+ COUNTER_INC(proc_destroy_label);
+}
+
+COUNTER_DECL(proc_init_label);
+static void
+test_proc_init_label(struct label *label)
+{
+
+ LABEL_INIT(label, MAGIC_PROC);
+ COUNTER_INC(proc_init_label);
+}
+
+COUNTER_DECL(socket_check_accept);
+static int
+test_socket_check_accept(struct ucred *cred, struct socket *so,
+ struct label *solabel)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(solabel, MAGIC_SOCKET);
+ COUNTER_INC(socket_check_accept);
+
+ return (0);
+}
+
+COUNTER_DECL(socket_check_bind);
+static int
+test_socket_check_bind(struct ucred *cred, struct socket *so,
+ struct label *solabel, struct sockaddr *sa)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(solabel, MAGIC_SOCKET);
+ COUNTER_INC(socket_check_bind);
+
+ return (0);
+}
+
+COUNTER_DECL(socket_check_connect);
+static int
+test_socket_check_connect(struct ucred *cred, struct socket *so,
+ struct label *solabel, struct sockaddr *sa)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(solabel, MAGIC_SOCKET);
+ COUNTER_INC(socket_check_connect);
+
+ return (0);
+}
+
+COUNTER_DECL(socket_check_deliver);
+static int
+test_socket_check_deliver(struct socket *so, struct label *solabel,
+ struct mbuf *m, struct label *mlabel)
+{
+
+ LABEL_CHECK(solabel, MAGIC_SOCKET);
+ LABEL_CHECK(mlabel, MAGIC_MBUF);
+ COUNTER_INC(socket_check_deliver);
+
+ return (0);
+}
+
+COUNTER_DECL(socket_check_listen);
+static int
+test_socket_check_listen(struct ucred *cred, struct socket *so,
+ struct label *solabel)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(solabel, MAGIC_SOCKET);
+ COUNTER_INC(socket_check_listen);
+
+ return (0);
+}
+
+COUNTER_DECL(socket_check_poll);
+static int
+test_socket_check_poll(struct ucred *cred, struct socket *so,
+ struct label *solabel)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(solabel, MAGIC_SOCKET);
+ COUNTER_INC(socket_check_poll);
+
+ return (0);
+}
+
+COUNTER_DECL(socket_check_receive);
+static int
+test_socket_check_receive(struct ucred *cred, struct socket *so,
+ struct label *solabel)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(solabel, MAGIC_SOCKET);
+ COUNTER_INC(socket_check_receive);
+
+ return (0);
+}
+
+COUNTER_DECL(socket_check_relabel);
+static int
+test_socket_check_relabel(struct ucred *cred, struct socket *so,
+ struct label *solabel, struct label *newlabel)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(solabel, MAGIC_SOCKET);
+ LABEL_CHECK(newlabel, MAGIC_SOCKET);
+ COUNTER_INC(socket_check_relabel);
+
+ return (0);
+}
+
+COUNTER_DECL(socket_check_send);
+static int
+test_socket_check_send(struct ucred *cred, struct socket *so,
+ struct label *solabel)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(solabel, MAGIC_SOCKET);
+ COUNTER_INC(socket_check_send);
+
+ return (0);
+}
+
+COUNTER_DECL(socket_check_stat);
+static int
+test_socket_check_stat(struct ucred *cred, struct socket *so,
+ struct label *solabel)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(solabel, MAGIC_SOCKET);
+ COUNTER_INC(socket_check_stat);
+
+ return (0);
+}
+
+COUNTER_DECL(socket_check_visible);
+static int
+test_socket_check_visible(struct ucred *cred, struct socket *so,
+ struct label *solabel)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(solabel, MAGIC_SOCKET);
+ COUNTER_INC(socket_check_visible);
+
+ return (0);
+}
+
+COUNTER_DECL(socket_copy_label);
+static void
+test_socket_copy_label(struct label *src, struct label *dest)
+{
+
+ LABEL_CHECK(src, MAGIC_SOCKET);
+ LABEL_CHECK(dest, MAGIC_SOCKET);
+ COUNTER_INC(socket_copy_label);
+}
+
+COUNTER_DECL(socket_create);
+static void
+test_socket_create(struct ucred *cred, struct socket *so,
+ struct label *solabel)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(solabel, MAGIC_SOCKET);
+ COUNTER_INC(socket_create);
+}
+
+COUNTER_DECL(socket_create_mbuf);
+static void
+test_socket_create_mbuf(struct socket *so, struct label *socketlabel,
+ struct mbuf *m, struct label *mlabel)
+{
+
+ LABEL_CHECK(socketlabel, MAGIC_SOCKET);
+ LABEL_CHECK(mlabel, MAGIC_MBUF);
+ COUNTER_INC(socket_create_mbuf);
+}
+
+COUNTER_DECL(socket_destroy_label);
+static void
+test_socket_destroy_label(struct label *label)
+{
+
+ LABEL_DESTROY(label, MAGIC_SOCKET);
+ COUNTER_INC(socket_destroy_label);
+}
+
+COUNTER_DECL(socket_externalize_label);
+static int
+test_socket_externalize_label(struct label *label, char *element_name,
+ struct sbuf *sb, int *claimed)
+{
+
+ LABEL_CHECK(label, MAGIC_SOCKET);
+ COUNTER_INC(socket_externalize_label);
+
+ return (0);
+}
+
+COUNTER_DECL(socket_init_label);
+static int
+test_socket_init_label(struct label *label, int flag)
+{
+
+ if (flag & M_WAITOK)
+ WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL,
+ "test_socket_init_label() at %s:%d", __FILE__,
+ __LINE__);
+
+ LABEL_INIT(label, MAGIC_SOCKET);
+ COUNTER_INC(socket_init_label);
+ return (0);
+}
+
+COUNTER_DECL(socket_internalize_label);
+static int
+test_socket_internalize_label(struct label *label, char *element_name,
+ char *element_data, int *claimed)
+{
+
+ LABEL_CHECK(label, MAGIC_SOCKET);
+ COUNTER_INC(socket_internalize_label);
+
+ return (0);
+}
+
+COUNTER_DECL(socket_newconn);
+static void
+test_socket_newconn(struct socket *oldso, struct label *oldsolabel,
+ struct socket *newso, struct label *newsolabel)
+{
+
+ LABEL_CHECK(oldsolabel, MAGIC_SOCKET);
+ LABEL_CHECK(newsolabel, MAGIC_SOCKET);
+ COUNTER_INC(socket_newconn);
+}
+
+COUNTER_DECL(socket_relabel);
+static void
+test_socket_relabel(struct ucred *cred, struct socket *so,
+ struct label *solabel, struct label *newlabel)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(solabel, MAGIC_SOCKET);
+ LABEL_CHECK(newlabel, MAGIC_SOCKET);
+ COUNTER_INC(socket_relabel);
+}
+
+COUNTER_DECL(socketpeer_destroy_label);
+static void
+test_socketpeer_destroy_label(struct label *label)
+{
+
+ LABEL_DESTROY(label, MAGIC_SOCKET);
+ COUNTER_INC(socketpeer_destroy_label);
+}
+
+COUNTER_DECL(socketpeer_externalize_label);
+static int
+test_socketpeer_externalize_label(struct label *label, char *element_name,
+ struct sbuf *sb, int *claimed)
+{
+
+ LABEL_CHECK(label, MAGIC_SOCKET);
+ COUNTER_INC(socketpeer_externalize_label);
+
+ return (0);
+}
+
+COUNTER_DECL(socketpeer_init_label);
+static int
+test_socketpeer_init_label(struct label *label, int flag)
+{
+
+ if (flag & M_WAITOK)
+ WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL,
+ "test_socketpeer_init_label() at %s:%d", __FILE__,
+ __LINE__);
+
+ LABEL_INIT(label, MAGIC_SOCKET);
+ COUNTER_INC(socketpeer_init_label);
+ return (0);
+}
+
+COUNTER_DECL(socketpeer_set_from_mbuf);
+static void
+test_socketpeer_set_from_mbuf(struct mbuf *m, struct label *mlabel,
+ struct socket *socket, struct label *socketpeerlabel)
+{
+
+ LABEL_CHECK(mlabel, MAGIC_MBUF);
+ LABEL_CHECK(socketpeerlabel, MAGIC_SOCKET);
+ COUNTER_INC(socketpeer_set_from_mbuf);
+}
+
+COUNTER_DECL(socketpeer_set_from_socket);
+static void
+test_socketpeer_set_from_socket(struct socket *oldso,
+ struct label *oldsolabel, struct socket *newso,
+ struct label *newsopeerlabel)
+{
+
+ LABEL_CHECK(oldsolabel, MAGIC_SOCKET);
+ LABEL_CHECK(newsopeerlabel, MAGIC_SOCKET);
+ COUNTER_INC(socketpeer_set_from_socket);
+}
+
+COUNTER_DECL(syncache_create);
+static void
+test_syncache_create(struct label *label, struct inpcb *inp)
+{
+
+ LABEL_CHECK(label, MAGIC_SYNCACHE);
+ COUNTER_INC(syncache_create);
+}
+
+COUNTER_DECL(syncache_create_mbuf);
+static void
+test_syncache_create_mbuf(struct label *sc_label, struct mbuf *m,
+ struct label *mlabel)
+{
+
+ LABEL_CHECK(sc_label, MAGIC_SYNCACHE);
+ LABEL_CHECK(mlabel, MAGIC_MBUF);
+ COUNTER_INC(syncache_create_mbuf);
+}
+
+COUNTER_DECL(syncache_destroy_label);
+static void
+test_syncache_destroy_label(struct label *label)
+{
+
+ LABEL_DESTROY(label, MAGIC_SYNCACHE);
+ COUNTER_INC(syncache_destroy_label);
+}
+
+COUNTER_DECL(syncache_init_label);
+static int
+test_syncache_init_label(struct label *label, int flag)
+{
+
+ if (flag & M_WAITOK)
+ WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL,
+ "test_syncache_init_label() at %s:%d", __FILE__,
+ __LINE__);
+ LABEL_INIT(label, MAGIC_SYNCACHE);
+ COUNTER_INC(syncache_init_label);
+ return (0);
+}
+
+COUNTER_DECL(system_check_acct);
+static int
+test_system_check_acct(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(vplabel, MAGIC_VNODE);
+ COUNTER_INC(system_check_acct);
+
+ return (0);
+}
+
+COUNTER_DECL(system_check_audit);
+static int
+test_system_check_audit(struct ucred *cred, void *record, int length)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ COUNTER_INC(system_check_audit);
+
+ return (0);
+}
+
+COUNTER_DECL(system_check_auditctl);
+static int
+test_system_check_auditctl(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(vplabel, MAGIC_VNODE);
+ COUNTER_INC(system_check_auditctl);
+
+ return (0);
+}
+
+COUNTER_DECL(system_check_auditon);
+static int
+test_system_check_auditon(struct ucred *cred, int cmd)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ COUNTER_INC(system_check_auditon);
+
+ return (0);
+}
+
+COUNTER_DECL(system_check_reboot);
+static int
+test_system_check_reboot(struct ucred *cred, int how)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ COUNTER_INC(system_check_reboot);
+
+ return (0);
+}
+
+COUNTER_DECL(system_check_swapoff);
+static int
+test_system_check_swapoff(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(vplabel, MAGIC_VNODE);
+ COUNTER_INC(system_check_swapoff);
+
+ return (0);
+}
+
+COUNTER_DECL(system_check_swapon);
+static int
+test_system_check_swapon(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(vplabel, MAGIC_VNODE);
+ COUNTER_INC(system_check_swapon);
+
+ return (0);
+}
+
+COUNTER_DECL(system_check_sysctl);
+static int
+test_system_check_sysctl(struct ucred *cred, struct sysctl_oid *oidp,
+ void *arg1, int arg2, struct sysctl_req *req)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ COUNTER_INC(system_check_sysctl);
+
+ return (0);
+}
+
+COUNTER_DECL(sysvmsg_cleanup);
+static void
+test_sysvmsg_cleanup(struct label *msglabel)
+{
+
+ LABEL_CHECK(msglabel, MAGIC_SYSV_MSG);
+ COUNTER_INC(sysvmsg_cleanup);
+}
+
+COUNTER_DECL(sysvmsg_create);
+static void
+test_sysvmsg_create(struct ucred *cred, struct msqid_kernel *msqkptr,
+ struct label *msqlabel, struct msg *msgptr, struct label *msglabel)
+{
+
+ LABEL_CHECK(msglabel, MAGIC_SYSV_MSG);
+ LABEL_CHECK(msqlabel, MAGIC_SYSV_MSQ);
+ COUNTER_INC(sysvmsg_create);
+}
+
+COUNTER_DECL(sysvmsg_destroy_label);
+static void
+test_sysvmsg_destroy_label(struct label *label)
+{
+
+ LABEL_DESTROY(label, MAGIC_SYSV_MSG);
+ COUNTER_INC(sysvmsg_destroy_label);
+}
+
+COUNTER_DECL(sysvmsg_init_label);
+static void
+test_sysvmsg_init_label(struct label *label)
+{
+ LABEL_INIT(label, MAGIC_SYSV_MSG);
+ COUNTER_INC(sysvmsg_init_label);
+}
+
+COUNTER_DECL(sysvmsq_check_msgmsq);
+static int
+test_sysvmsq_check_msgmsq(struct ucred *cred, struct msg *msgptr,
+ struct label *msglabel, struct msqid_kernel *msqkptr,
+ struct label *msqklabel)
+{
+
+ LABEL_CHECK(msqklabel, MAGIC_SYSV_MSQ);
+ LABEL_CHECK(msglabel, MAGIC_SYSV_MSG);
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ COUNTER_INC(sysvmsq_check_msgmsq);
+
+ return (0);
+}
+
+COUNTER_DECL(sysvmsq_check_msgrcv);
+static int
+test_sysvmsq_check_msgrcv(struct ucred *cred, struct msg *msgptr,
+ struct label *msglabel)
+{
+
+ LABEL_CHECK(msglabel, MAGIC_SYSV_MSG);
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ COUNTER_INC(sysvmsq_check_msgrcv);
+
+ return (0);
+}
+
+COUNTER_DECL(sysvmsq_check_msgrmid);
+static int
+test_sysvmsq_check_msgrmid(struct ucred *cred, struct msg *msgptr,
+ struct label *msglabel)
+{
+
+ LABEL_CHECK(msglabel, MAGIC_SYSV_MSG);
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ COUNTER_INC(sysvmsq_check_msgrmid);
+
+ return (0);
+}
+
+COUNTER_DECL(sysvmsq_check_msqget);
+static int
+test_sysvmsq_check_msqget(struct ucred *cred,
+ struct msqid_kernel *msqkptr, struct label *msqklabel)
+{
+
+ LABEL_CHECK(msqklabel, MAGIC_SYSV_MSQ);
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ COUNTER_INC(sysvmsq_check_msqget);
+
+ return (0);
+}
+
+COUNTER_DECL(sysvmsq_check_msqsnd);
+static int
+test_sysvmsq_check_msqsnd(struct ucred *cred,
+ struct msqid_kernel *msqkptr, struct label *msqklabel)
+{
+
+ LABEL_CHECK(msqklabel, MAGIC_SYSV_MSQ);
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ COUNTER_INC(sysvmsq_check_msqsnd);
+
+ return (0);
+}
+
+COUNTER_DECL(sysvmsq_check_msqrcv);
+static int
+test_sysvmsq_check_msqrcv(struct ucred *cred,
+ struct msqid_kernel *msqkptr, struct label *msqklabel)
+{
+
+ LABEL_CHECK(msqklabel, MAGIC_SYSV_MSQ);
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ COUNTER_INC(sysvmsq_check_msqrcv);
+
+ return (0);
+}
+
+COUNTER_DECL(sysvmsq_check_msqctl);
+static int
+test_sysvmsq_check_msqctl(struct ucred *cred,
+ struct msqid_kernel *msqkptr, struct label *msqklabel, int cmd)
+{
+
+ LABEL_CHECK(msqklabel, MAGIC_SYSV_MSQ);
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ COUNTER_INC(sysvmsq_check_msqctl);
+
+ return (0);
+}
+
+COUNTER_DECL(sysvmsq_cleanup);
+static void
+test_sysvmsq_cleanup(struct label *msqlabel)
+{
+
+ LABEL_CHECK(msqlabel, MAGIC_SYSV_MSQ);
+ COUNTER_INC(sysvmsq_cleanup);
+}
+
+COUNTER_DECL(sysvmsq_create);
+static void
+test_sysvmsq_create(struct ucred *cred,
+ struct msqid_kernel *msqkptr, struct label *msqlabel)
+{
+
+ LABEL_CHECK(msqlabel, MAGIC_SYSV_MSQ);
+ COUNTER_INC(sysvmsq_create);
+}
+
+COUNTER_DECL(sysvmsq_destroy_label);
+static void
+test_sysvmsq_destroy_label(struct label *label)
+{
+
+ LABEL_DESTROY(label, MAGIC_SYSV_MSQ);
+ COUNTER_INC(sysvmsq_destroy_label);
+}
+
+COUNTER_DECL(sysvmsq_init_label);
+static void
+test_sysvmsq_init_label(struct label *label)
+{
+ LABEL_INIT(label, MAGIC_SYSV_MSQ);
+ COUNTER_INC(sysvmsq_init_label);
+}
+
+COUNTER_DECL(sysvsem_check_semctl);
+static int
+test_sysvsem_check_semctl(struct ucred *cred,
+ struct semid_kernel *semakptr, struct label *semaklabel, int cmd)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(semaklabel, MAGIC_SYSV_SEM);
+ COUNTER_INC(sysvsem_check_semctl);
+
+ return (0);
+}
+
+COUNTER_DECL(sysvsem_check_semget);
+static int
+test_sysvsem_check_semget(struct ucred *cred,
+ struct semid_kernel *semakptr, struct label *semaklabel)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(semaklabel, MAGIC_SYSV_SEM);
+ COUNTER_INC(sysvsem_check_semget);
+
+ return (0);
+}
+
+COUNTER_DECL(sysvsem_check_semop);
+static int
+test_sysvsem_check_semop(struct ucred *cred,
+ struct semid_kernel *semakptr, struct label *semaklabel, size_t accesstype)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(semaklabel, MAGIC_SYSV_SEM);
+ COUNTER_INC(sysvsem_check_semop);
+
+ return (0);
+}
+
+COUNTER_DECL(sysvsem_cleanup);
+static void
+test_sysvsem_cleanup(struct label *semalabel)
+{
+
+ LABEL_CHECK(semalabel, MAGIC_SYSV_SEM);
+ COUNTER_INC(sysvsem_cleanup);
+}
+
+COUNTER_DECL(sysvsem_create);
+static void
+test_sysvsem_create(struct ucred *cred, struct semid_kernel *semakptr,
+ struct label *semalabel)
+{
+
+ LABEL_CHECK(semalabel, MAGIC_SYSV_SEM);
+ COUNTER_INC(sysvsem_create);
+}
+
+COUNTER_DECL(sysvsem_destroy_label);
+static void
+test_sysvsem_destroy_label(struct label *label)
+{
+
+ LABEL_DESTROY(label, MAGIC_SYSV_SEM);
+ COUNTER_INC(sysvsem_destroy_label);
+}
+
+COUNTER_DECL(sysvsem_init_label);
+static void
+test_sysvsem_init_label(struct label *label)
+{
+ LABEL_INIT(label, MAGIC_SYSV_SEM);
+ COUNTER_INC(sysvsem_init_label);
+}
+
+COUNTER_DECL(sysvshm_check_shmat);
+static int
+test_sysvshm_check_shmat(struct ucred *cred,
+ struct shmid_kernel *shmsegptr, struct label *shmseglabel, int shmflg)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(shmseglabel, MAGIC_SYSV_SHM);
+ COUNTER_INC(sysvshm_check_shmat);
+
+ return (0);
+}
+
+COUNTER_DECL(sysvshm_check_shmctl);
+static int
+test_sysvshm_check_shmctl(struct ucred *cred,
+ struct shmid_kernel *shmsegptr, struct label *shmseglabel, int cmd)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(shmseglabel, MAGIC_SYSV_SHM);
+ COUNTER_INC(sysvshm_check_shmctl);
+
+ return (0);
+}
+
+COUNTER_DECL(sysvshm_check_shmdt);
+static int
+test_sysvshm_check_shmdt(struct ucred *cred,
+ struct shmid_kernel *shmsegptr, struct label *shmseglabel)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(shmseglabel, MAGIC_SYSV_SHM);
+ COUNTER_INC(sysvshm_check_shmdt);
+
+ return (0);
+}
+
+COUNTER_DECL(sysvshm_check_shmget);
+static int
+test_sysvshm_check_shmget(struct ucred *cred,
+ struct shmid_kernel *shmsegptr, struct label *shmseglabel, int shmflg)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(shmseglabel, MAGIC_SYSV_SHM);
+ COUNTER_INC(sysvshm_check_shmget);
+
+ return (0);
+}
+
+COUNTER_DECL(sysvshm_cleanup);
+static void
+test_sysvshm_cleanup(struct label *shmlabel)
+{
+
+ LABEL_CHECK(shmlabel, MAGIC_SYSV_SHM);
+ COUNTER_INC(sysvshm_cleanup);
+}
+
+COUNTER_DECL(sysvshm_create);
+static void
+test_sysvshm_create(struct ucred *cred, struct shmid_kernel *shmsegptr,
+ struct label *shmlabel)
+{
+
+ LABEL_CHECK(shmlabel, MAGIC_SYSV_SHM);
+ COUNTER_INC(sysvshm_create);
+}
+
+COUNTER_DECL(sysvshm_destroy_label);
+static void
+test_sysvshm_destroy_label(struct label *label)
+{
+
+ LABEL_DESTROY(label, MAGIC_SYSV_SHM);
+ COUNTER_INC(sysvshm_destroy_label);
+}
+
+COUNTER_DECL(sysvshm_init_label);
+static void
+test_sysvshm_init_label(struct label *label)
+{
+ LABEL_INIT(label, MAGIC_SYSV_SHM);
+ COUNTER_INC(sysvshm_init_label);
+}
+
+COUNTER_DECL(thread_userret);
+static void
+test_thread_userret(struct thread *td)
+{
+
+ COUNTER_INC(thread_userret);
+}
+
+COUNTER_DECL(vnode_associate_extattr);
+static int
+test_vnode_associate_extattr(struct mount *mp, struct label *mplabel,
+ struct vnode *vp, struct label *vplabel)
+{
+
+ LABEL_CHECK(mplabel, MAGIC_MOUNT);
+ LABEL_CHECK(vplabel, MAGIC_VNODE);
+ COUNTER_INC(vnode_associate_extattr);
+
+ return (0);
+}
+
+COUNTER_DECL(vnode_associate_singlelabel);
+static void
+test_vnode_associate_singlelabel(struct mount *mp, struct label *mplabel,
+ struct vnode *vp, struct label *vplabel)
+{
+
+ LABEL_CHECK(mplabel, MAGIC_MOUNT);
+ LABEL_CHECK(vplabel, MAGIC_VNODE);
+ COUNTER_INC(vnode_associate_singlelabel);
+}
+
+COUNTER_DECL(vnode_check_access);
+static int
+test_vnode_check_access(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, accmode_t accmode)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(vplabel, MAGIC_VNODE);
+ COUNTER_INC(vnode_check_access);
+
+ return (0);
+}
+
+COUNTER_DECL(vnode_check_chdir);
+static int
+test_vnode_check_chdir(struct ucred *cred, struct vnode *dvp,
+ struct label *dvplabel)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(dvplabel, MAGIC_VNODE);
+ COUNTER_INC(vnode_check_chdir);
+
+ return (0);
+}
+
+COUNTER_DECL(vnode_check_chroot);
+static int
+test_vnode_check_chroot(struct ucred *cred, struct vnode *dvp,
+ struct label *dvplabel)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(dvplabel, MAGIC_VNODE);
+ COUNTER_INC(vnode_check_chroot);
+
+ return (0);
+}
+
+COUNTER_DECL(vnode_check_create);
+static int
+test_vnode_check_create(struct ucred *cred, struct vnode *dvp,
+ struct label *dvplabel, struct componentname *cnp, struct vattr *vap)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(dvplabel, MAGIC_VNODE);
+ COUNTER_INC(vnode_check_create);
+
+ return (0);
+}
+
+COUNTER_DECL(vnode_check_deleteacl);
+static int
+test_vnode_check_deleteacl(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, acl_type_t type)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(vplabel, MAGIC_VNODE);
+ COUNTER_INC(vnode_check_deleteacl);
+
+ return (0);
+}
+
+COUNTER_DECL(vnode_check_deleteextattr);
+static int
+test_vnode_check_deleteextattr(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, int attrnamespace, const char *name)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(vplabel, MAGIC_VNODE);
+ COUNTER_INC(vnode_check_deleteextattr);
+
+ return (0);
+}
+
+COUNTER_DECL(vnode_check_exec);
+static int
+test_vnode_check_exec(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, struct image_params *imgp,
+ struct label *execlabel)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(vplabel, MAGIC_VNODE);
+ LABEL_CHECK(execlabel, MAGIC_CRED);
+ COUNTER_INC(vnode_check_exec);
+
+ return (0);
+}
+
+COUNTER_DECL(vnode_check_getacl);
+static int
+test_vnode_check_getacl(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, acl_type_t type)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(vplabel, MAGIC_VNODE);
+ COUNTER_INC(vnode_check_getacl);
+
+ return (0);
+}
+
+COUNTER_DECL(vnode_check_getextattr);
+static int
+test_vnode_check_getextattr(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, int attrnamespace, const char *name,
+ struct uio *uio)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(vplabel, MAGIC_VNODE);
+ COUNTER_INC(vnode_check_getextattr);
+
+ return (0);
+}
+
+COUNTER_DECL(vnode_check_link);
+static int
+test_vnode_check_link(struct ucred *cred, struct vnode *dvp,
+ struct label *dvplabel, struct vnode *vp, struct label *vplabel,
+ struct componentname *cnp)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(dvplabel, MAGIC_VNODE);
+ LABEL_CHECK(vplabel, MAGIC_VNODE);
+ COUNTER_INC(vnode_check_link);
+
+ return (0);
+}
+
+COUNTER_DECL(vnode_check_listextattr);
+static int
+test_vnode_check_listextattr(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, int attrnamespace)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(vplabel, MAGIC_VNODE);
+ COUNTER_INC(vnode_check_listextattr);
+
+ return (0);
+}
+
+COUNTER_DECL(vnode_check_lookup);
+static int
+test_vnode_check_lookup(struct ucred *cred, struct vnode *dvp,
+ struct label *dvplabel, struct componentname *cnp)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(dvplabel, MAGIC_VNODE);
+ COUNTER_INC(vnode_check_lookup);
+
+ return (0);
+}
+
+COUNTER_DECL(vnode_check_mmap);
+static int
+test_vnode_check_mmap(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, int prot, int flags)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(vplabel, MAGIC_VNODE);
+ COUNTER_INC(vnode_check_mmap);
+
+ return (0);
+}
+
+COUNTER_DECL(vnode_check_open);
+static int
+test_vnode_check_open(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, accmode_t accmode)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(vplabel, MAGIC_VNODE);
+ COUNTER_INC(vnode_check_open);
+
+ return (0);
+}
+
+COUNTER_DECL(vnode_check_poll);
+static int
+test_vnode_check_poll(struct ucred *active_cred, struct ucred *file_cred,
+ struct vnode *vp, struct label *vplabel)
+{
+
+ LABEL_CHECK(active_cred->cr_label, MAGIC_CRED);
+ if (file_cred != NULL)
+ LABEL_CHECK(file_cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(vplabel, MAGIC_VNODE);
+ COUNTER_INC(vnode_check_poll);
+
+ return (0);
+}
+
+COUNTER_DECL(vnode_check_read);
+static int
+test_vnode_check_read(struct ucred *active_cred, struct ucred *file_cred,
+ struct vnode *vp, struct label *vplabel)
+{
+
+ LABEL_CHECK(active_cred->cr_label, MAGIC_CRED);
+ if (file_cred != NULL)
+ LABEL_CHECK(file_cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(vplabel, MAGIC_VNODE);
+ COUNTER_INC(vnode_check_read);
+
+ return (0);
+}
+
+COUNTER_DECL(vnode_check_readdir);
+static int
+test_vnode_check_readdir(struct ucred *cred, struct vnode *dvp,
+ struct label *dvplabel)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(dvplabel, MAGIC_VNODE);
+ COUNTER_INC(vnode_check_readdir);
+
+ return (0);
+}
+
+COUNTER_DECL(vnode_check_readlink);
+static int
+test_vnode_check_readlink(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(vplabel, MAGIC_VNODE);
+ COUNTER_INC(vnode_check_readlink);
+
+ return (0);
+}
+
+COUNTER_DECL(vnode_check_relabel);
+static int
+test_vnode_check_relabel(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, struct label *newlabel)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(vplabel, MAGIC_VNODE);
+ LABEL_CHECK(newlabel, MAGIC_VNODE);
+ COUNTER_INC(vnode_check_relabel);
+
+ return (0);
+}
+
+COUNTER_DECL(vnode_check_rename_from);
+static int
+test_vnode_check_rename_from(struct ucred *cred, struct vnode *dvp,
+ struct label *dvplabel, struct vnode *vp, struct label *vplabel,
+ struct componentname *cnp)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(dvplabel, MAGIC_VNODE);
+ LABEL_CHECK(vplabel, MAGIC_VNODE);
+ COUNTER_INC(vnode_check_rename_from);
+
+ return (0);
+}
+
+COUNTER_DECL(vnode_check_rename_to);
+static int
+test_vnode_check_rename_to(struct ucred *cred, struct vnode *dvp,
+ struct label *dvplabel, struct vnode *vp, struct label *vplabel,
+ int samedir, struct componentname *cnp)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(dvplabel, MAGIC_VNODE);
+ LABEL_CHECK(vplabel, MAGIC_VNODE);
+ COUNTER_INC(vnode_check_rename_to);
+
+ return (0);
+}
+
+COUNTER_DECL(vnode_check_revoke);
+static int
+test_vnode_check_revoke(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(vplabel, MAGIC_VNODE);
+ COUNTER_INC(vnode_check_revoke);
+
+ return (0);
+}
+
+COUNTER_DECL(vnode_check_setacl);
+static int
+test_vnode_check_setacl(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, acl_type_t type, struct acl *acl)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(vplabel, MAGIC_VNODE);
+ COUNTER_INC(vnode_check_setacl);
+
+ return (0);
+}
+
+COUNTER_DECL(vnode_check_setextattr);
+static int
+test_vnode_check_setextattr(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, int attrnamespace, const char *name,
+ struct uio *uio)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(vplabel, MAGIC_VNODE);
+ COUNTER_INC(vnode_check_setextattr);
+
+ return (0);
+}
+
+COUNTER_DECL(vnode_check_setflags);
+static int
+test_vnode_check_setflags(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, u_long flags)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(vplabel, MAGIC_VNODE);
+ COUNTER_INC(vnode_check_setflags);
+
+ return (0);
+}
+
+COUNTER_DECL(vnode_check_setmode);
+static int
+test_vnode_check_setmode(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, mode_t mode)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(vplabel, MAGIC_VNODE);
+ COUNTER_INC(vnode_check_setmode);
+
+ return (0);
+}
+
+COUNTER_DECL(vnode_check_setowner);
+static int
+test_vnode_check_setowner(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, uid_t uid, gid_t gid)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(vplabel, MAGIC_VNODE);
+ COUNTER_INC(vnode_check_setowner);
+
+ return (0);
+}
+
+COUNTER_DECL(vnode_check_setutimes);
+static int
+test_vnode_check_setutimes(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, struct timespec atime, struct timespec mtime)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(vplabel, MAGIC_VNODE);
+ COUNTER_INC(vnode_check_setutimes);
+
+ return (0);
+}
+
+COUNTER_DECL(vnode_check_stat);
+static int
+test_vnode_check_stat(struct ucred *active_cred, struct ucred *file_cred,
+ struct vnode *vp, struct label *vplabel)
+{
+
+ LABEL_CHECK(active_cred->cr_label, MAGIC_CRED);
+ if (file_cred != NULL)
+ LABEL_CHECK(file_cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(vplabel, MAGIC_VNODE);
+ COUNTER_INC(vnode_check_stat);
+
+ return (0);
+}
+
+COUNTER_DECL(vnode_check_unlink);
+static int
+test_vnode_check_unlink(struct ucred *cred, struct vnode *dvp,
+ struct label *dvplabel, struct vnode *vp, struct label *vplabel,
+ struct componentname *cnp)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(dvplabel, MAGIC_VNODE);
+ LABEL_CHECK(vplabel, MAGIC_VNODE);
+ COUNTER_INC(vnode_check_unlink);
+
+ return (0);
+}
+
+COUNTER_DECL(vnode_check_write);
+static int
+test_vnode_check_write(struct ucred *active_cred,
+ struct ucred *file_cred, struct vnode *vp, struct label *vplabel)
+{
+
+ LABEL_CHECK(active_cred->cr_label, MAGIC_CRED);
+ if (file_cred != NULL)
+ LABEL_CHECK(file_cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(vplabel, MAGIC_VNODE);
+ COUNTER_INC(vnode_check_write);
+
+ return (0);
+}
+
+COUNTER_DECL(vnode_copy_label);
+static void
+test_vnode_copy_label(struct label *src, struct label *dest)
+{
+
+ LABEL_CHECK(src, MAGIC_VNODE);
+ LABEL_CHECK(dest, MAGIC_VNODE);
+ COUNTER_INC(vnode_copy_label);
+}
+
+COUNTER_DECL(vnode_create_extattr);
+static int
+test_vnode_create_extattr(struct ucred *cred, struct mount *mp,
+ struct label *mplabel, struct vnode *dvp, struct label *dvplabel,
+ struct vnode *vp, struct label *vplabel, struct componentname *cnp)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(mplabel, MAGIC_MOUNT);
+ LABEL_CHECK(dvplabel, MAGIC_VNODE);
+ COUNTER_INC(vnode_create_extattr);
+
+ return (0);
+}
+
+COUNTER_DECL(vnode_destroy_label);
+static void
+test_vnode_destroy_label(struct label *label)
+{
+
+ LABEL_DESTROY(label, MAGIC_VNODE);
+ COUNTER_INC(vnode_destroy_label);
+}
+
+COUNTER_DECL(vnode_execve_transition);
+static void
+test_vnode_execve_transition(struct ucred *old, struct ucred *new,
+ struct vnode *vp, struct label *filelabel,
+ struct label *interpvplabel, struct image_params *imgp,
+ struct label *execlabel)
+{
+
+ LABEL_CHECK(old->cr_label, MAGIC_CRED);
+ LABEL_CHECK(new->cr_label, MAGIC_CRED);
+ LABEL_CHECK(filelabel, MAGIC_VNODE);
+ LABEL_CHECK(interpvplabel, MAGIC_VNODE);
+ LABEL_CHECK(execlabel, MAGIC_CRED);
+ COUNTER_INC(vnode_execve_transition);
+}
+
+COUNTER_DECL(vnode_execve_will_transition);
+static int
+test_vnode_execve_will_transition(struct ucred *old, struct vnode *vp,
+ struct label *filelabel, struct label *interpvplabel,
+ struct image_params *imgp, struct label *execlabel)
+{
+
+ LABEL_CHECK(old->cr_label, MAGIC_CRED);
+ LABEL_CHECK(filelabel, MAGIC_VNODE);
+ LABEL_CHECK(interpvplabel, MAGIC_VNODE);
+ LABEL_CHECK(execlabel, MAGIC_CRED);
+ COUNTER_INC(vnode_execve_will_transition);
+
+ return (0);
+}
+
+COUNTER_DECL(vnode_externalize_label);
+static int
+test_vnode_externalize_label(struct label *label, char *element_name,
+ struct sbuf *sb, int *claimed)
+{
+
+ LABEL_CHECK(label, MAGIC_VNODE);
+ COUNTER_INC(vnode_externalize_label);
+
+ return (0);
+}
+
+COUNTER_DECL(vnode_init_label);
+static void
+test_vnode_init_label(struct label *label)
+{
+
+ LABEL_INIT(label, MAGIC_VNODE);
+ COUNTER_INC(vnode_init_label);
+}
+
+COUNTER_DECL(vnode_internalize_label);
+static int
+test_vnode_internalize_label(struct label *label, char *element_name,
+ char *element_data, int *claimed)
+{
+
+ LABEL_CHECK(label, MAGIC_VNODE);
+ COUNTER_INC(vnode_internalize_label);
+
+ return (0);
+}
+
+COUNTER_DECL(vnode_relabel);
+static void
+test_vnode_relabel(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, struct label *label)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(vplabel, MAGIC_VNODE);
+ LABEL_CHECK(label, MAGIC_VNODE);
+ COUNTER_INC(vnode_relabel);
+}
+
+COUNTER_DECL(vnode_setlabel_extattr);
+static int
+test_vnode_setlabel_extattr(struct ucred *cred, struct vnode *vp,
+ struct label *vplabel, struct label *intlabel)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ LABEL_CHECK(vplabel, MAGIC_VNODE);
+ LABEL_CHECK(intlabel, MAGIC_VNODE);
+ COUNTER_INC(vnode_setlabel_extattr);
+
+ return (0);
+}
+
+static struct mac_policy_ops test_ops =
+{
+ .mpo_bpfdesc_check_receive = test_bpfdesc_check_receive,
+ .mpo_bpfdesc_create = test_bpfdesc_create,
+ .mpo_bpfdesc_create_mbuf = test_bpfdesc_create_mbuf,
+ .mpo_bpfdesc_destroy_label = test_bpfdesc_destroy_label,
+ .mpo_bpfdesc_init_label = test_bpfdesc_init_label,
+
+ .mpo_cred_check_relabel = test_cred_check_relabel,
+ .mpo_cred_check_visible = test_cred_check_visible,
+ .mpo_cred_copy_label = test_cred_copy_label,
+ .mpo_cred_create_init = test_cred_create_init,
+ .mpo_cred_create_swapper = test_cred_create_swapper,
+ .mpo_cred_destroy_label = test_cred_destroy_label,
+ .mpo_cred_externalize_label = test_cred_externalize_label,
+ .mpo_cred_init_label = test_cred_init_label,
+ .mpo_cred_internalize_label = test_cred_internalize_label,
+ .mpo_cred_relabel = test_cred_relabel,
+
+ .mpo_devfs_create_device = test_devfs_create_device,
+ .mpo_devfs_create_directory = test_devfs_create_directory,
+ .mpo_devfs_create_symlink = test_devfs_create_symlink,
+ .mpo_devfs_destroy_label = test_devfs_destroy_label,
+ .mpo_devfs_init_label = test_devfs_init_label,
+ .mpo_devfs_update = test_devfs_update,
+ .mpo_devfs_vnode_associate = test_devfs_vnode_associate,
+
+ .mpo_ifnet_check_relabel = test_ifnet_check_relabel,
+ .mpo_ifnet_check_transmit = test_ifnet_check_transmit,
+ .mpo_ifnet_copy_label = test_ifnet_copy_label,
+ .mpo_ifnet_create = test_ifnet_create,
+ .mpo_ifnet_create_mbuf = test_ifnet_create_mbuf,
+ .mpo_ifnet_destroy_label = test_ifnet_destroy_label,
+ .mpo_ifnet_externalize_label = test_ifnet_externalize_label,
+ .mpo_ifnet_init_label = test_ifnet_init_label,
+ .mpo_ifnet_internalize_label = test_ifnet_internalize_label,
+ .mpo_ifnet_relabel = test_ifnet_relabel,
+
+ .mpo_syncache_destroy_label = test_syncache_destroy_label,
+ .mpo_syncache_init_label = test_syncache_init_label,
+
+ .mpo_sysvmsg_destroy_label = test_sysvmsg_destroy_label,
+ .mpo_sysvmsg_init_label = test_sysvmsg_init_label,
+
+ .mpo_sysvmsq_destroy_label = test_sysvmsq_destroy_label,
+ .mpo_sysvmsq_init_label = test_sysvmsq_init_label,
+
+ .mpo_sysvsem_destroy_label = test_sysvsem_destroy_label,
+ .mpo_sysvsem_init_label = test_sysvsem_init_label,
+
+ .mpo_sysvshm_destroy_label = test_sysvshm_destroy_label,
+ .mpo_sysvshm_init_label = test_sysvshm_init_label,
+
+ .mpo_inpcb_check_deliver = test_inpcb_check_deliver,
+ .mpo_inpcb_check_visible = test_inpcb_check_visible,
+ .mpo_inpcb_create = test_inpcb_create,
+ .mpo_inpcb_create_mbuf = test_inpcb_create_mbuf,
+ .mpo_inpcb_destroy_label = test_inpcb_destroy_label,
+ .mpo_inpcb_init_label = test_inpcb_init_label,
+ .mpo_inpcb_sosetlabel = test_inpcb_sosetlabel,
+
+ .mpo_ip6q_create = test_ip6q_create,
+ .mpo_ip6q_destroy_label = test_ip6q_destroy_label,
+ .mpo_ip6q_init_label = test_ip6q_init_label,
+ .mpo_ip6q_match = test_ip6q_match,
+ .mpo_ip6q_reassemble = test_ip6q_reassemble,
+ .mpo_ip6q_update = test_ip6q_update,
+
+ .mpo_ipq_create = test_ipq_create,
+ .mpo_ipq_destroy_label = test_ipq_destroy_label,
+ .mpo_ipq_init_label = test_ipq_init_label,
+ .mpo_ipq_match = test_ipq_match,
+ .mpo_ipq_reassemble = test_ipq_reassemble,
+ .mpo_ipq_update = test_ipq_update,
+
+ .mpo_kenv_check_dump = test_kenv_check_dump,
+ .mpo_kenv_check_get = test_kenv_check_get,
+ .mpo_kenv_check_set = test_kenv_check_set,
+ .mpo_kenv_check_unset = test_kenv_check_unset,
+
+ .mpo_kld_check_load = test_kld_check_load,
+ .mpo_kld_check_stat = test_kld_check_stat,
+
+ .mpo_mbuf_copy_label = test_mbuf_copy_label,
+ .mpo_mbuf_destroy_label = test_mbuf_destroy_label,
+ .mpo_mbuf_init_label = test_mbuf_init_label,
+
+ .mpo_mount_check_stat = test_mount_check_stat,
+ .mpo_mount_create = test_mount_create,
+ .mpo_mount_destroy_label = test_mount_destroy_label,
+ .mpo_mount_init_label = test_mount_init_label,
+
+ .mpo_netatalk_aarp_send = test_netatalk_aarp_send,
+
+ .mpo_netinet_arp_send = test_netinet_arp_send,
+ .mpo_netinet_fragment = test_netinet_fragment,
+ .mpo_netinet_icmp_reply = test_netinet_icmp_reply,
+ .mpo_netinet_icmp_replyinplace = test_netinet_icmp_replyinplace,
+ .mpo_netinet_igmp_send = test_netinet_igmp_send,
+ .mpo_netinet_tcp_reply = test_netinet_tcp_reply,
+
+ .mpo_netinet6_nd6_send = test_netinet6_nd6_send,
+
+ .mpo_pipe_check_ioctl = test_pipe_check_ioctl,
+ .mpo_pipe_check_poll = test_pipe_check_poll,
+ .mpo_pipe_check_read = test_pipe_check_read,
+ .mpo_pipe_check_relabel = test_pipe_check_relabel,
+ .mpo_pipe_check_stat = test_pipe_check_stat,
+ .mpo_pipe_check_write = test_pipe_check_write,
+ .mpo_pipe_copy_label = test_pipe_copy_label,
+ .mpo_pipe_create = test_pipe_create,
+ .mpo_pipe_destroy_label = test_pipe_destroy_label,
+ .mpo_pipe_externalize_label = test_pipe_externalize_label,
+ .mpo_pipe_init_label = test_pipe_init_label,
+ .mpo_pipe_internalize_label = test_pipe_internalize_label,
+ .mpo_pipe_relabel = test_pipe_relabel,
+
+ .mpo_posixsem_check_getvalue = test_posixsem_check_getvalue,
+ .mpo_posixsem_check_open = test_posixsem_check_open,
+ .mpo_posixsem_check_post = test_posixsem_check_post,
+ .mpo_posixsem_check_stat = test_posixsem_check_stat,
+ .mpo_posixsem_check_unlink = test_posixsem_check_unlink,
+ .mpo_posixsem_check_wait = test_posixsem_check_wait,
+ .mpo_posixsem_create = test_posixsem_create,
+ .mpo_posixsem_destroy_label = test_posixsem_destroy_label,
+ .mpo_posixsem_init_label = test_posixsem_init_label,
+
+ .mpo_posixshm_check_mmap = test_posixshm_check_mmap,
+ .mpo_posixshm_check_open = test_posixshm_check_open,
+ .mpo_posixshm_check_stat = test_posixshm_check_stat,
+ .mpo_posixshm_check_truncate = test_posixshm_check_truncate,
+ .mpo_posixshm_check_unlink = test_posixshm_check_unlink,
+ .mpo_posixshm_create = test_posixshm_create,
+ .mpo_posixshm_destroy_label = test_posixshm_destroy_label,
+ .mpo_posixshm_init_label = test_posixshm_init_label,
+
+ .mpo_proc_check_debug = test_proc_check_debug,
+ .mpo_proc_check_sched = test_proc_check_sched,
+ .mpo_proc_check_setaudit = test_proc_check_setaudit,
+ .mpo_proc_check_setaudit_addr = test_proc_check_setaudit_addr,
+ .mpo_proc_check_setauid = test_proc_check_setauid,
+ .mpo_proc_check_seteuid = test_proc_check_seteuid,
+ .mpo_proc_check_setegid = test_proc_check_setegid,
+ .mpo_proc_check_setgid = test_proc_check_setgid,
+ .mpo_proc_check_setgroups = test_proc_check_setgroups,
+ .mpo_proc_check_setregid = test_proc_check_setregid,
+ .mpo_proc_check_setresgid = test_proc_check_setresgid,
+ .mpo_proc_check_setresuid = test_proc_check_setresuid,
+ .mpo_proc_check_setreuid = test_proc_check_setreuid,
+ .mpo_proc_check_setuid = test_proc_check_setuid,
+ .mpo_proc_check_signal = test_proc_check_signal,
+ .mpo_proc_check_wait = test_proc_check_wait,
+ .mpo_proc_destroy_label = test_proc_destroy_label,
+ .mpo_proc_init_label = test_proc_init_label,
+
+ .mpo_socket_check_accept = test_socket_check_accept,
+ .mpo_socket_check_bind = test_socket_check_bind,
+ .mpo_socket_check_connect = test_socket_check_connect,
+ .mpo_socket_check_deliver = test_socket_check_deliver,
+ .mpo_socket_check_listen = test_socket_check_listen,
+ .mpo_socket_check_poll = test_socket_check_poll,
+ .mpo_socket_check_receive = test_socket_check_receive,
+ .mpo_socket_check_relabel = test_socket_check_relabel,
+ .mpo_socket_check_send = test_socket_check_send,
+ .mpo_socket_check_stat = test_socket_check_stat,
+ .mpo_socket_check_visible = test_socket_check_visible,
+ .mpo_socket_copy_label = test_socket_copy_label,
+ .mpo_socket_create = test_socket_create,
+ .mpo_socket_create_mbuf = test_socket_create_mbuf,
+ .mpo_socket_destroy_label = test_socket_destroy_label,
+ .mpo_socket_externalize_label = test_socket_externalize_label,
+ .mpo_socket_init_label = test_socket_init_label,
+ .mpo_socket_internalize_label = test_socket_internalize_label,
+ .mpo_socket_newconn = test_socket_newconn,
+ .mpo_socket_relabel = test_socket_relabel,
+
+ .mpo_socketpeer_destroy_label = test_socketpeer_destroy_label,
+ .mpo_socketpeer_externalize_label = test_socketpeer_externalize_label,
+ .mpo_socketpeer_init_label = test_socketpeer_init_label,
+ .mpo_socketpeer_set_from_mbuf = test_socketpeer_set_from_mbuf,
+ .mpo_socketpeer_set_from_socket = test_socketpeer_set_from_socket,
+
+ .mpo_syncache_create = test_syncache_create,
+ .mpo_syncache_create_mbuf = test_syncache_create_mbuf,
+
+ .mpo_system_check_acct = test_system_check_acct,
+ .mpo_system_check_audit = test_system_check_audit,
+ .mpo_system_check_auditctl = test_system_check_auditctl,
+ .mpo_system_check_auditon = test_system_check_auditon,
+ .mpo_system_check_reboot = test_system_check_reboot,
+ .mpo_system_check_swapoff = test_system_check_swapoff,
+ .mpo_system_check_swapon = test_system_check_swapon,
+ .mpo_system_check_sysctl = test_system_check_sysctl,
+
+ .mpo_vnode_check_access = test_vnode_check_access,
+ .mpo_sysvmsg_cleanup = test_sysvmsg_cleanup,
+ .mpo_sysvmsg_create = test_sysvmsg_create,
+
+ .mpo_sysvmsq_check_msgmsq = test_sysvmsq_check_msgmsq,
+ .mpo_sysvmsq_check_msgrcv = test_sysvmsq_check_msgrcv,
+ .mpo_sysvmsq_check_msgrmid = test_sysvmsq_check_msgrmid,
+ .mpo_sysvmsq_check_msqget = test_sysvmsq_check_msqget,
+ .mpo_sysvmsq_check_msqsnd = test_sysvmsq_check_msqsnd,
+ .mpo_sysvmsq_check_msqrcv = test_sysvmsq_check_msqrcv,
+ .mpo_sysvmsq_check_msqctl = test_sysvmsq_check_msqctl,
+ .mpo_sysvmsq_cleanup = test_sysvmsq_cleanup,
+ .mpo_sysvmsq_create = test_sysvmsq_create,
+
+ .mpo_sysvsem_check_semctl = test_sysvsem_check_semctl,
+ .mpo_sysvsem_check_semget = test_sysvsem_check_semget,
+ .mpo_sysvsem_check_semop = test_sysvsem_check_semop,
+ .mpo_sysvsem_cleanup = test_sysvsem_cleanup,
+ .mpo_sysvsem_create = test_sysvsem_create,
+
+ .mpo_sysvshm_check_shmat = test_sysvshm_check_shmat,
+ .mpo_sysvshm_check_shmctl = test_sysvshm_check_shmctl,
+ .mpo_sysvshm_check_shmdt = test_sysvshm_check_shmdt,
+ .mpo_sysvshm_check_shmget = test_sysvshm_check_shmget,
+ .mpo_sysvshm_cleanup = test_sysvshm_cleanup,
+ .mpo_sysvshm_create = test_sysvshm_create,
+
+ .mpo_thread_userret = test_thread_userret,
+
+ .mpo_vnode_associate_extattr = test_vnode_associate_extattr,
+ .mpo_vnode_associate_singlelabel = test_vnode_associate_singlelabel,
+ .mpo_vnode_check_chdir = test_vnode_check_chdir,
+ .mpo_vnode_check_chroot = test_vnode_check_chroot,
+ .mpo_vnode_check_create = test_vnode_check_create,
+ .mpo_vnode_check_deleteacl = test_vnode_check_deleteacl,
+ .mpo_vnode_check_deleteextattr = test_vnode_check_deleteextattr,
+ .mpo_vnode_check_exec = test_vnode_check_exec,
+ .mpo_vnode_check_getacl = test_vnode_check_getacl,
+ .mpo_vnode_check_getextattr = test_vnode_check_getextattr,
+ .mpo_vnode_check_link = test_vnode_check_link,
+ .mpo_vnode_check_listextattr = test_vnode_check_listextattr,
+ .mpo_vnode_check_lookup = test_vnode_check_lookup,
+ .mpo_vnode_check_mmap = test_vnode_check_mmap,
+ .mpo_vnode_check_open = test_vnode_check_open,
+ .mpo_vnode_check_poll = test_vnode_check_poll,
+ .mpo_vnode_check_read = test_vnode_check_read,
+ .mpo_vnode_check_readdir = test_vnode_check_readdir,
+ .mpo_vnode_check_readlink = test_vnode_check_readlink,
+ .mpo_vnode_check_relabel = test_vnode_check_relabel,
+ .mpo_vnode_check_rename_from = test_vnode_check_rename_from,
+ .mpo_vnode_check_rename_to = test_vnode_check_rename_to,
+ .mpo_vnode_check_revoke = test_vnode_check_revoke,
+ .mpo_vnode_check_setacl = test_vnode_check_setacl,
+ .mpo_vnode_check_setextattr = test_vnode_check_setextattr,
+ .mpo_vnode_check_setflags = test_vnode_check_setflags,
+ .mpo_vnode_check_setmode = test_vnode_check_setmode,
+ .mpo_vnode_check_setowner = test_vnode_check_setowner,
+ .mpo_vnode_check_setutimes = test_vnode_check_setutimes,
+ .mpo_vnode_check_stat = test_vnode_check_stat,
+ .mpo_vnode_check_unlink = test_vnode_check_unlink,
+ .mpo_vnode_check_write = test_vnode_check_write,
+ .mpo_vnode_copy_label = test_vnode_copy_label,
+ .mpo_vnode_create_extattr = test_vnode_create_extattr,
+ .mpo_vnode_destroy_label = test_vnode_destroy_label,
+ .mpo_vnode_execve_transition = test_vnode_execve_transition,
+ .mpo_vnode_execve_will_transition = test_vnode_execve_will_transition,
+ .mpo_vnode_externalize_label = test_vnode_externalize_label,
+ .mpo_vnode_init_label = test_vnode_init_label,
+ .mpo_vnode_internalize_label = test_vnode_internalize_label,
+ .mpo_vnode_relabel = test_vnode_relabel,
+ .mpo_vnode_setlabel_extattr = test_vnode_setlabel_extattr,
+};
+
+#define TEST_OBJECTS (MPC_OBJECT_CRED | \
+ MPC_OBJECT_PROC | \
+ MPC_OBJECT_VNODE | \
+ MPC_OBJECT_INPCB | \
+ MPC_OBJECT_SOCKET | \
+ MPC_OBJECT_DEVFS | \
+ MPC_OBJECT_MBUF | \
+ MPC_OBJECT_IPQ | \
+ MPC_OBJECT_IFNET | \
+ MPC_OBJECT_BPFDESC | \
+ MPC_OBJECT_PIPE | \
+ MPC_OBJECT_MOUNT | \
+ MPC_OBJECT_POSIXSEM | \
+ MPC_OBJECT_POSIXSHM | \
+ MPC_OBJECT_SYSVMSG | \
+ MPC_OBJECT_SYSVMSQ | \
+ MPC_OBJECT_SYSVSEM | \
+ MPC_OBJECT_SYSVSHM | \
+ MPC_OBJECT_SYNCACHE)
+
+MAC_POLICY_SET(&test_ops, mac_test, "TrustedBSD MAC/Test",
+ MPC_LOADTIME_FLAG_UNLOADOK, &test_slot, TEST_OBJECTS);
OpenPOWER on IntegriCloud