summaryrefslogtreecommitdiffstats
path: root/sys/security/lomac
diff options
context:
space:
mode:
authorgreen <green@FreeBSD.org>2001-11-19 22:34:06 +0000
committergreen <green@FreeBSD.org>2001-11-19 22:34:06 +0000
commitbeff1147748a3755545f834914bec7f7174b7648 (patch)
tree855390076025818f6fea90037cfe44711457356a /sys/security/lomac
downloadFreeBSD-src-beff1147748a3755545f834914bec7f7174b7648.zip
FreeBSD-src-beff1147748a3755545f834914bec7f7174b7648.tar.gz
Import LOMAC preliminary release 2.0.0 in src/sys/security. These files may
be modified and do not have to remain on the vendor branch. http://opensource.nailabs.com/lomac/index.html Sponsored by: DARPA, NAI Labs (CBOSS project)
Diffstat (limited to 'sys/security/lomac')
-rw-r--r--sys/security/lomac/kernel_interface.c506
-rw-r--r--sys/security/lomac/kernel_interface.h101
-rw-r--r--sys/security/lomac/kernel_lkm.c288
-rw-r--r--sys/security/lomac/kernel_log.c199
-rw-r--r--sys/security/lomac/kernel_log.h77
-rw-r--r--sys/security/lomac/kernel_mediate.c289
-rw-r--r--sys/security/lomac/kernel_mediate.h68
-rw-r--r--sys/security/lomac/kernel_mmap.c553
-rw-r--r--sys/security/lomac/kernel_monitor.c206
-rw-r--r--sys/security/lomac/kernel_monitor.h62
-rw-r--r--sys/security/lomac/kernel_pipe.c241
-rw-r--r--sys/security/lomac/kernel_pipe.h44
-rw-r--r--sys/security/lomac/kernel_plm.c382
-rw-r--r--sys/security/lomac/kernel_plm.h45
-rw-r--r--sys/security/lomac/kernel_socket.c784
-rw-r--r--sys/security/lomac/kernel_socket.h45
-rw-r--r--sys/security/lomac/kernel_util.c696
-rw-r--r--sys/security/lomac/kernel_util.h64
-rw-r--r--sys/security/lomac/lomac.h114
-rw-r--r--sys/security/lomac/lomacfs.h115
-rw-r--r--sys/security/lomac/lomacfs_subr.c127
-rw-r--r--sys/security/lomac/lomacfs_vfsops.c199
-rw-r--r--sys/security/lomac/lomacfs_vnops.c1150
-rw-r--r--sys/security/lomac/lomacio.h59
-rw-r--r--sys/security/lomac/policy_plm.h119
-rw-r--r--sys/security/lomac/syscall_gate.c125
-rw-r--r--sys/security/lomac/syscall_gate.h56
27 files changed, 6714 insertions, 0 deletions
diff --git a/sys/security/lomac/kernel_interface.c b/sys/security/lomac/kernel_interface.c
new file mode 100644
index 0000000..d617523
--- /dev/null
+++ b/sys/security/lomac/kernel_interface.c
@@ -0,0 +1,506 @@
+/*-
+ * Copyright (c) 2001 Networks Associates Technologies, Inc.
+ * All rights reserved.
+ *
+ * This software was developed for the FreeBSD Project 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.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * 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.
+ *
+ * $Id$
+ * $FreeBSD$
+ */
+
+#include <sys/param.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/proc.h>
+#include <sys/systm.h>
+#include <sys/vnode.h>
+#include <sys/pipe.h>
+#include <sys/socketvar.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+#include <vm/vm_map.h>
+
+#include "kernel_interface.h"
+#include "lomacfs.h"
+#include "kernel_log.h"
+
+/*
+ * Reuse the eflags field of proc.p_vmspace->vm_map.header (since it is
+ * currently not used for anything but a placeholder, and won't change
+ * generally...) as storage for our process-based information.
+ *
+ * This is the only really effective way to make thread-based MAC
+ * easy.
+ */
+
+#define p_eflags p_vmspace->vm_map.header.eflags
+#define EF_HIGHEST_LEVEL 0x00010000
+#define EF_LOWEST_LEVEL 0x00020000
+#define EF_LEVEL_MASK 0x00030000
+#define EF_ATTR_NONETDEMOTE 0x00040000
+#define EF_ATTR_NODEMOTE 0x00080000
+#define EF_ATTR_MASK 0x000c0000
+
+static u_int
+level2subjectbits(level_t level) {
+
+ switch (level) {
+ case LOMAC_HIGHEST_LEVEL:
+ return (EF_HIGHEST_LEVEL);
+ case LOMAC_LOWEST_LEVEL:
+ return (EF_LOWEST_LEVEL);
+ default:
+ panic("level2subjectbits: invalid level %d\n", level);
+ }
+}
+
+static level_t
+subjectbits2level(u_int flags) {
+
+ switch (flags & EF_LEVEL_MASK) {
+ case EF_HIGHEST_LEVEL:
+ /*
+ * During an execve(), the kernel's original execve() creates a
+ * new vmspace and puts it into use before it has been initialized
+ * by us to contain a subject level. Since this is the only case
+ * when a subject may have a level not set, pretend that it
+ * is just a high-level file, and allow the lomacfs_open() to then
+ * succeed.
+ */
+ case 0:
+ return (LOMAC_HIGHEST_LEVEL);
+ case EF_LOWEST_LEVEL:
+ return (LOMAC_LOWEST_LEVEL);
+ default:
+ panic("subjectbits2level: invalid flags %#x\n", flags);
+ }
+}
+
+static u_int
+attr2subjectbits(u_int attr) {
+ u_int bits = 0;
+
+ if (attr & LOMAC_ATTR_NONETDEMOTE)
+ bits |= EF_ATTR_NONETDEMOTE;
+ if (attr & LOMAC_ATTR_NODEMOTE)
+ bits |= EF_ATTR_NODEMOTE;
+ return (bits);
+}
+
+static u_int
+subjectbits2attr(u_int bits) {
+ u_int attr = 0;
+
+ if (bits & EF_ATTR_NONETDEMOTE)
+ attr |= LOMAC_ATTR_NONETDEMOTE;
+ if (bits & EF_ATTR_NODEMOTE)
+ attr |= LOMAC_ATTR_NODEMOTE;
+ return (attr);
+}
+
+static int
+subject_lock(lomac_subject_t *p, int read) {
+#ifdef USES_LOCKMGR
+ int hadlock;
+
+ hadlock = PROC_LOCKED(p);
+ if (hadlock)
+ PROC_UNLOCK(p);
+#endif
+ if (read)
+ vm_map_lock_read(&p->p_vmspace->vm_map);
+ else
+ vm_map_lock(&p->p_vmspace->vm_map);
+#ifdef USES_LOCKMGR
+ return (hadlock);
+#else
+ return (0);
+#endif
+}
+
+static void
+subject_unlock(lomac_subject_t *p, int read, int hadlock) {
+
+ if (read)
+ vm_map_unlock_read(&p->p_vmspace->vm_map);
+ else
+ vm_map_unlock(&p->p_vmspace->vm_map);
+#ifdef USES_LOCKMGR
+ if (hadlock)
+ PROC_LOCK(p);
+#endif
+}
+
+
+void
+init_subject_lattr(lomac_subject_t *p, lattr_t *lattr) {
+ int s;
+
+ s = subject_lock(p, 0);
+ p->p_eflags = level2subjectbits(lattr->level) |
+ attr2subjectbits(lattr->flags);
+ subject_unlock(p, 0, s);
+}
+
+/*
+ * Set/get the subject level on a process. The process must not be able
+ * to change, so either the process must be locked on entry or it must
+ * be held in exclusivity otherwise (executing on behalf of via a syscall,
+ * including as EITHER child or parent in a fork).
+ */
+void
+set_subject_lattr(lomac_subject_t *p, lattr_t lattr) {
+ int s;
+
+#ifdef INVARIANTS
+ do {
+ lattr_t oslattr;
+
+ get_subject_lattr(p, &oslattr);
+ if (lomac_must_demote(&lattr, &oslattr))
+ panic("raising subject level");
+ } while (0);
+#endif /* !INVARIANTS */
+ s = subject_lock(p, 0);
+ p->p_eflags = (p->p_eflags & ~(EF_LEVEL_MASK | EF_ATTR_MASK)) |
+ level2subjectbits(lattr.level) |
+ attr2subjectbits(lattr.flags);
+ subject_unlock(p, 0, s);
+ kernel_vm_drop_perms(curthread, &lattr);
+}
+
+void
+get_subject_lattr(lomac_subject_t *p, lattr_t *lattr) {
+ int s;
+
+ s = subject_lock(p, 1);
+ lattr->level = subjectbits2level(p->p_eflags);
+ lattr->flags = subjectbits2attr(p->p_eflags);
+ subject_unlock(p, 1, s);
+}
+
+static __inline u_int
+level2lvnodebits(level_t level) {
+
+ switch (level) {
+ case LOMAC_HIGHEST_LEVEL:
+ return (LN_HIGHEST_LEVEL);
+ case LOMAC_LOWEST_LEVEL:
+ return (LN_LOWEST_LEVEL);
+ default:
+ panic("level2lvnodebits: invalid level %d\n", level);
+ }
+}
+
+static __inline level_t
+lvnodebits2level(u_int flags) {
+
+ switch (flags & LN_LEVEL_MASK) {
+ case LN_HIGHEST_LEVEL:
+ return (LOMAC_HIGHEST_LEVEL);
+ case LN_LOWEST_LEVEL:
+ return (LOMAC_LOWEST_LEVEL);
+ default:
+ panic("lvnodebits2level: invalid flags %#x\n", flags);
+ }
+}
+
+static __inline unsigned int
+attr2lvnodebits(unsigned int attr) {
+ unsigned int bits = 0;
+
+ if (attr & LOMAC_ATTR_LOWWRITE)
+ bits |= LN_ATTR_LOWWRITE;
+ if (attr & LOMAC_ATTR_LOWNOOPEN)
+ bits |= LN_ATTR_LOWNOOPEN;
+ if (attr & LOMAC_ATTR_NONETDEMOTE)
+ bits |= LN_ATTR_NONETDEMOTE;
+ if (attr & LOMAC_ATTR_NODEMOTE)
+ bits |= LN_ATTR_NODEMOTE;
+ return (bits);
+}
+
+static __inline unsigned int
+lvnodebits2attr(unsigned int bits) {
+ unsigned int attr = 0;
+
+ if (bits & LN_ATTR_LOWWRITE)
+ attr |= LOMAC_ATTR_LOWWRITE;
+ if (bits & LN_ATTR_LOWNOOPEN)
+ attr |= LOMAC_ATTR_LOWNOOPEN;
+ if (bits & LN_ATTR_NONETDEMOTE)
+ attr |= LOMAC_ATTR_NONETDEMOTE;
+ if (bits & LN_ATTR_NODEMOTE)
+ attr |= LOMAC_ATTR_NODEMOTE;
+ return (attr);
+}
+
+/*
+ * These flags correspond to the same ones set in lomac_node{}s.
+ */
+#define UV_LEVEL_MASK 0x08000000
+#define UV_LOWEST_LEVEL 0x00000000
+#define UV_HIGHEST_LEVEL 0x08000000
+#define UV_ATTR_LOWWRITE 0x10000000
+#define UV_ATTR_LOWNOOPEN 0x20000000
+#define UV_ATTR_NONETDEMOTE 0x40000000
+#define UV_ATTR_NODEMOTE 0x80000000
+#define UV_ATTR_MASK 0xf0000000
+
+static __inline u_int
+level2uvnodebits(level_t level) {
+
+ switch (level) {
+ case LOMAC_HIGHEST_LEVEL:
+ return (UV_HIGHEST_LEVEL);
+ case LOMAC_LOWEST_LEVEL:
+ return (UV_LOWEST_LEVEL);
+ default:
+ panic("level2uvnodebits: invalid level %d\n", level);
+ }
+}
+
+static __inline level_t
+uvnodebits2level(u_int flags) {
+
+ switch (flags & UV_LEVEL_MASK) {
+ case UV_HIGHEST_LEVEL:
+ return (LOMAC_HIGHEST_LEVEL);
+ case UV_LOWEST_LEVEL:
+ return (LOMAC_LOWEST_LEVEL);
+ default:
+ panic("uvnodebits2level: invalid flags %#x\n", flags);
+ }
+}
+
+static __inline u_int
+attr2uvnodebits(u_int attr) {
+ unsigned int bits = 0;
+
+ if (attr & LOMAC_ATTR_LOWWRITE)
+ bits |= UV_ATTR_LOWWRITE;
+ if (attr & LOMAC_ATTR_LOWNOOPEN)
+ bits |= UV_ATTR_LOWNOOPEN;
+ if (attr & LOMAC_ATTR_NONETDEMOTE)
+ bits |= UV_ATTR_NONETDEMOTE;
+ if (attr & LOMAC_ATTR_NODEMOTE)
+ bits |= UV_ATTR_NODEMOTE;
+ return (bits);
+}
+
+static __inline u_int
+uvnodebits2attr(u_int bits) {
+ unsigned int attr = 0;
+
+ if (bits & UV_ATTR_LOWWRITE)
+ attr |= LOMAC_ATTR_LOWWRITE;
+ if (bits & UV_ATTR_LOWNOOPEN)
+ attr |= LOMAC_ATTR_LOWNOOPEN;
+ if (bits & UV_ATTR_NONETDEMOTE)
+ attr |= LOMAC_ATTR_NONETDEMOTE;
+ if (bits & UV_ATTR_NODEMOTE)
+ attr |= LOMAC_ATTR_NODEMOTE;
+ return (attr);
+}
+
+#define OBJ_LOWEST_LEVEL 0x8000 /* the highest level is implicit */
+
+/*
+ * This code marks pipes with levels. We use a previously unnused bit
+ * in the pipe_state field of struct pipe to store the level
+ * information. Bit clear means LOMAC_HIGHEST_LEVEL, bit set means
+ * LOMAC_LOWEST_LEVEL. Since new pipes have clear bits by default,
+ * using clear bit as highest causes new pipes to start at the highest
+ * level automatically.
+ */
+#define PIPE_LEVEL_LOWEST 0x10000000
+
+/* This code marks sockets created by socketpair() with levels. It
+ * uses a previouslt unused bit in the so_state field of struct socket
+ * to store the level information. Bit clear means
+ * LOMAC_HIGHEST_LEVEL, bit set means LOMAC_LOWEST_LEVEL. Since new
+ * sockets have clear bits by default, using clear bit as highest
+ * causes new sockets to start at the highest level automatically.
+ */
+#define SOCKET_LEVEL_LOWEST 0x4000
+
+void
+set_object_lattr(lomac_object_t *obj, lattr_t lattr) {
+ struct vnode *vp;
+ struct lomac_node *ln;
+ vm_object_t object;
+ struct pipe *pipe;
+ struct socket *socket;
+
+ switch (obj->lo_type) {
+ case LO_TYPE_LVNODE:
+ KASSERT(VISLOMAC(obj->lo_object.vnode),
+ ("not a LOMACFS vnode"));
+ ln = VTOLOMAC(obj->lo_object.vnode);
+ ln->ln_flags =
+ (ln->ln_flags & ~(LN_LEVEL_MASK | LN_ATTR_MASK)) |
+ level2lvnodebits(lattr.level) |
+ attr2lvnodebits(lattr.flags);
+ break;
+ case LO_TYPE_UVNODE:
+ vp = obj->lo_object.vnode;
+ KASSERT(!VISLOMAC(vp), ("is a LOMACFS vnode"));
+ VI_LOCK(vp);
+ vp->v_flag = (vp->v_flag & ~(UV_LEVEL_MASK | UV_ATTR_MASK)) |
+ level2uvnodebits(lattr.level) |
+ attr2uvnodebits(lattr.flags);
+ VI_UNLOCK(vp);
+ break;
+ case LO_TYPE_VM_OBJECT:
+ object = obj->lo_object.vm_object;
+ KASSERT(object->type != OBJT_VNODE, ("object has a vnode"));
+ KASSERT(object->backing_object == NULL,
+ ("is a backing object"));
+ if (lattr.level == LOMAC_HIGHEST_LEVEL)
+ vm_object_clear_flag(object, OBJ_LOWEST_LEVEL);
+ else
+ vm_object_set_flag(object, OBJ_LOWEST_LEVEL);
+ KASSERT(lattr.flags == 0,
+ ("cannot set attr on a vm_object"));
+ break;
+ case LO_TYPE_PIPE:
+ pipe = obj->lo_object.pipe;
+ KASSERT(pipe->pipe_peer == NULL ||
+ (pipe->pipe_state & PIPE_LEVEL_LOWEST) ==
+ (pipe->pipe_peer->pipe_state & PIPE_LEVEL_LOWEST),
+ ("pipe attrs unsynchronized"));
+ if (lattr.level == LOMAC_HIGHEST_LEVEL)
+ pipe->pipe_state &= ~PIPE_LEVEL_LOWEST;
+ else
+ pipe->pipe_state |= PIPE_LEVEL_LOWEST;
+ pipe = pipe->pipe_peer;
+ if (pipe != NULL) {
+ if (lattr.level == LOMAC_HIGHEST_LEVEL)
+ pipe->pipe_state &= ~PIPE_LEVEL_LOWEST;
+ else
+ pipe->pipe_state |= PIPE_LEVEL_LOWEST;
+ }
+ KASSERT(lattr.flags == 0, ("cannot set attr on a pipe"));
+ break;
+ case LO_TYPE_SOCKETPAIR:
+ socket = obj->lo_object.socket;
+ /* KASSERT that socket peer levels are synchronized */
+ if (lattr.level == LOMAC_HIGHEST_LEVEL)
+ socket->so_state &= ~SOCKET_LEVEL_LOWEST;
+ else
+ socket->so_state |= SOCKET_LEVEL_LOWEST;
+#ifdef NOT_YET
+ pipe = pipe->pipe_peer;
+ if (pipe != NULL) {
+ if (lattr.level == LOMAC_HIGHEST_LEVEL)
+ pipe->pipe_state &= ~PIPE_LEVEL_LOWEST;
+ else
+ pipe->pipe_state |= PIPE_LEVEL_LOWEST;
+ }
+ KASSERT(lattr.flags == 0, ("cannot set attr on a pipe"));
+#endif
+ break;
+ default:
+ panic("set_object_lattr: invalid lo_type %d", obj->lo_type);
+ }
+}
+
+void
+get_object_lattr(const lomac_object_t *obj, lattr_t *lattr) {
+ struct vnode *vp;
+ struct lomac_node *ln;
+ vm_object_t object;
+ struct pipe *pipe;
+ struct socket *socket;
+
+ switch (obj->lo_type) {
+ case LO_TYPE_LVNODE:
+ KASSERT(VISLOMAC(obj->lo_object.vnode),
+ ("not a LOMACFS vnode"));
+ ln = VTOLOMAC(obj->lo_object.vnode);
+ lattr->level = lvnodebits2level(ln->ln_flags);
+ lattr->flags = lvnodebits2attr(ln->ln_flags);
+ break;
+ case LO_TYPE_UVNODE:
+ vp = obj->lo_object.vnode;
+ KASSERT(!VISLOMAC(vp), ("is a LOMACFS vnode"));
+ VI_LOCK(vp);
+ lattr->level = uvnodebits2level(vp->v_flag);
+ lattr->flags = uvnodebits2attr(vp->v_flag);
+ VI_UNLOCK(vp);
+ break;
+ case LO_TYPE_VM_OBJECT:
+ object = obj->lo_object.vm_object;
+ KASSERT(object->type != OBJT_VNODE, ("object has a vnode"));
+ KASSERT(object->backing_object == NULL,
+ ("is a backing object"));
+ lattr->level = (object->flags & OBJ_LOWEST_LEVEL) ?
+ LOMAC_LOWEST_LEVEL : LOMAC_HIGHEST_LEVEL;
+ lattr->flags = 0;
+ break;
+ case LO_TYPE_PIPE:
+ pipe = obj->lo_object.pipe;
+ lattr->level = (pipe->pipe_state & PIPE_LEVEL_LOWEST) ?
+ LOMAC_LOWEST_LEVEL : LOMAC_HIGHEST_LEVEL;
+ lattr->flags = 0;
+ break;
+ case LO_TYPE_SOCKETPAIR:
+ socket = obj->lo_object.socket;
+ lattr->level = (socket->so_state & SOCKET_LEVEL_LOWEST) ?
+ LOMAC_LOWEST_LEVEL : LOMAC_HIGHEST_LEVEL;
+ lattr->flags = 0;
+ break;
+ default:
+ panic("get_object_level: invalid lo_type %d", obj->lo_type);
+ }
+}
+
+/*
+ * Flag certain procs, like init(8) and kthreads, as "invincible".
+ */
+int
+subject_do_not_demote(lomac_subject_t *subj) {
+ int inv = 0;
+
+ if (subj->p_pid == 1) {
+ inv = 1;
+ } else {
+ int had_lock = PROC_LOCKED(subj);
+
+ if (!had_lock)
+ PROC_LOCK(subj);
+ if (subj->p_flag & P_SYSTEM)
+ inv = 1;
+ if (!had_lock)
+ PROC_UNLOCK(subj);
+ }
+ return (inv);
+}
diff --git a/sys/security/lomac/kernel_interface.h b/sys/security/lomac/kernel_interface.h
new file mode 100644
index 0000000..f9db05e
--- /dev/null
+++ b/sys/security/lomac/kernel_interface.h
@@ -0,0 +1,101 @@
+/*-
+ * Copyright (c) 2001 Networks Associates Technologies, Inc.
+ * All rights reserved.
+ *
+ * This software was developed for the FreeBSD Project 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.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * 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.
+ *
+ * $Id$
+ * $FreeBSD$
+ */
+
+#ifndef KERNEL_INTERFACE_H
+#define KERNEL_INTERFACE_H
+
+#include <sys/param.h>
+#include <sys/proc.h>
+#include <sys/sbuf.h>
+#include <sys/vnode.h>
+
+#include <vm/vm.h>
+#include <vm/vm_object.h>
+
+#include "lomac.h"
+
+
+/*
+ * We do not yet implement any categories. We use lattr_t's flags
+ * field to implement the "LOMAC_ATTR_LOWWRITE" exception. When
+ * this bit is set on a file, lowest-level processes can write to
+ * the file, regardless of the file's level.
+ *
+ * There is also the LOMAC_ATTR_LOWNOOPEN flag, which prevents the
+ * opening of a given object to subjects with a lower level than its
+ * own.
+ *
+ * LOMAC_ATTR_NONETDEMOTE is set on subjects to prevent demotion on
+ * network reads; LOMAC_ATTR_NODEMOTE is set on subjects to prevent
+ * all demotion. Both of these will effectively set a high-level
+ * subject as very trusted (and must be used sparingly).
+ */
+#define LOMAC_ATTR_LOWWRITE 0x00010000
+#define LOMAC_ATTR_LOWNOOPEN 0x00020000
+#define LOMAC_ATTR_NONETDEMOTE 0x00040000
+#define LOMAC_ATTR_NODEMOTE 0x00080000
+
+typedef struct proc lomac_subject_t;
+typedef struct lomac_object {
+ enum lomac_object_type {
+ LO_TYPE_LVNODE, /* LOMAC vnode */
+ LO_TYPE_UVNODE, /* underlying vnode */
+ LO_TYPE_VM_OBJECT, /* VM object, not OBJT_VNODE */
+ LO_TYPE_PIPE, /* pipe */
+ LO_TYPE_SOCKETPAIR /* local-domain socket in socketpair */
+ } lo_type;
+ union {
+ struct vnode *vnode;
+ vm_object_t vm_object;
+ struct pipe *pipe;
+ struct socket *socket;
+ } lo_object;
+} lomac_object_t;
+typedef struct sbuf lomac_log_t;
+
+void init_subject_lattr(lomac_subject_t *, lattr_t *);
+void set_subject_lattr(lomac_subject_t *, lattr_t);
+void get_subject_lattr(lomac_subject_t *, lattr_t *);
+void set_object_lattr(lomac_object_t *, lattr_t);
+void get_object_lattr(const lomac_object_t *, lattr_t *);
+int subject_do_not_demote(lomac_subject_t *);
+#if 0
+void subject_propogate_lattr(lomac_subject_t *);
+#endif
+void kernel_vm_drop_perms(struct thread *, lattr_t *);
+
+#endif /* KERNEL_INTERFACE_H */
diff --git a/sys/security/lomac/kernel_lkm.c b/sys/security/lomac/kernel_lkm.c
new file mode 100644
index 0000000..3da6816
--- /dev/null
+++ b/sys/security/lomac/kernel_lkm.c
@@ -0,0 +1,288 @@
+/*-
+ * Copyright (c) 2001 Networks Associates Technologies, Inc.
+ * All rights reserved.
+ *
+ * This software was developed for the FreeBSD Project 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.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * 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.
+ *
+ * $Id$
+ * $FreeBSD$
+ */
+
+#include <sys/param.h>
+#include <sys/conf.h>
+#include <sys/errno.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/mount.h>
+#include <sys/linker.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/namei.h>
+#include <sys/proc.h>
+#include <sys/systm.h>
+
+#include "kernel_interface.h"
+#include "kernel_mediate.h"
+#include "kernel_plm.h"
+#include "kernel_util.h"
+#include "kernel_pipe.h"
+#include "kernel_socket.h"
+#include "lomacfs.h"
+#include "lomacio.h"
+
+static d_ioctl_t lomac_ioctl;
+
+#define CDEV_MAJOR 207
+#define LOMAC_MINOR 0
+
+static struct cdevsw lomac_cdevsw = {
+ /* open */ (d_open_t *)nullop,
+ /* close */ (d_open_t *)nullop,
+ /* read */ noread,
+ /* write */ nowrite,
+ /* ioctl */ lomac_ioctl,
+ /* poll */ nopoll,
+ /* mmap */ nommap,
+ /* strategy */ nostrategy,
+ /* name */ "lomac",
+ /* maj */ CDEV_MAJOR,
+ /* dump */ nodump,
+ /* psize */ nopsize,
+ /* flags */ 0,
+};
+
+static dev_t lomac_dev = NULL;
+
+int
+lomac_ioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct thread *td) {
+ struct nameidata nd;
+ struct proc *p;
+ struct proc *targp;
+ struct lomac_fioctl *fio;
+ lomac_object_t lobj;
+ lattr_t lattr;
+ int error;
+
+ p = td->td_proc;
+ switch (cmd) {
+ case LIOGETPLEVEL:
+ targp = pfind(*(int *)data);
+ if (targp == NULL)
+ return (ESRCH);
+ if (p_cansee(p, targp) != 0) {
+ PROC_UNLOCK(targp);
+ return (ESRCH);
+ }
+ get_subject_lattr(targp, &lattr);
+ *(level_t *)data = lattr.level;
+ PROC_UNLOCK(targp);
+ return (0);
+ case LIOGETFLEVEL:
+ fio = (struct lomac_fioctl *)data;
+ NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | NOOBJ, UIO_SYSSPACE,
+ fio->path, td);
+ if ((error = namei(&nd)) != 0)
+ return (error);
+ if (VISLOMAC(nd.ni_vp))
+ lobj.lo_type = LO_TYPE_LVNODE;
+ else
+ lobj.lo_type = LO_TYPE_UVNODE;
+ lobj.lo_object.vnode = nd.ni_vp;
+ get_object_lattr(&lobj, &lattr);
+ *(level_t *)&fio->level = lattr.level;
+ NDFREE(&nd, NDF_ONLY_PNBUF);
+ vput(nd.ni_vp);
+ return (error);
+ case LIOGETFLATTR:
+ fio = (struct lomac_fioctl *)data;
+ NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | NOOBJ, UIO_SYSSPACE,
+ fio->path, td);
+ if ((error = namei(&nd)) != 0)
+ return (error);
+ if (VISLOMAC(nd.ni_vp))
+ lobj.lo_type = LO_TYPE_LVNODE;
+ else
+ lobj.lo_type = LO_TYPE_UVNODE;
+ lobj.lo_object.vnode = nd.ni_vp;
+ get_object_lattr(&lobj, (lattr_t *)&fio->level);
+ NDFREE(&nd, NDF_ONLY_PNBUF);
+ vput(nd.ni_vp);
+ return (error);
+ case LIOPMAKELOWLEVEL:
+ lattr.level = LOMAC_LOWEST_LEVEL;
+ lattr.flags = 0;
+ set_subject_lattr(p, lattr);
+ return (0);
+ default:
+ return (ENOTTY);
+ }
+}
+
+int (*old_execve)(struct proc *, void *);
+#ifdef __i386__
+int (*old_sysarch)(struct proc *, void *);
+#endif
+
+/*
+ * This is "borrowed" from kern_module.c and MUST be kept in synch!
+ */
+struct module {
+ TAILQ_ENTRY(module) link; /* chain together all modules */
+ TAILQ_ENTRY(module) flink; /* all modules in a file */
+ struct linker_file* file; /* file which contains this module */
+ int refs; /* reference count */
+ int id; /* unique id number */
+ char *name; /* module name */
+ modeventhand_t handler; /* event handler */
+ void *arg; /* argument for handler */
+ modspecific_t data; /* module specific data */
+};
+
+static int
+lomac_modevent(module_t module, int event, void *unused) {
+ static int initialized_procs = 0;
+ static int initialized_syscalls = 0;
+ static int initialized_pipes = 0;
+ static int initialized_sockets = 0;
+ static int initialized_vm = 0;
+ static linker_file_t kernlf;
+ int error;
+
+ switch ((enum modeventtype)event) {
+ case MOD_LOAD:
+ if (!lomac_plm_initialized)
+ return (EINVAL);
+ kernlf = linker_kernel_file;
+ old_execve =
+ (int (*)(struct proc *, void *))linker_file_lookup_symbol(
+ kernlf, "execve", 1);
+ if (old_execve == NULL)
+ return (ENOENT);
+#ifdef __i386__
+ old_sysarch =
+ (int (*)(struct proc *, void *))linker_file_lookup_symbol(
+ kernlf, "sysarch", 1);
+ if (old_sysarch == NULL)
+ return (ENOENT);
+#endif
+ error = lomac_initialize_procs();
+ if (error)
+ break;
+ initialized_procs = 1;
+ error = lomac_initialize_syscalls();
+ if (error)
+ break;
+ initialized_syscalls = 1;
+ error = lomac_initialize_pipes();
+ if (error)
+ break;
+ initialized_pipes = 1;
+ error = lomac_initialize_sockets();
+ if (error)
+ break;
+ initialized_sockets = 1;
+ lomac_dev = make_dev(&lomac_cdevsw, LOMAC_MINOR, UID_ROOT,
+ GID_WHEEL, 0666, "lomac");
+ linker_kernel_file = module->file;
+ error = vfs_mount(curthread, "lomacfs", "/", 0, NULL);
+ if (error)
+ return (error);
+ error = lomac_initialize_cwds();
+ if (error)
+ return (error);
+ printf("LOMAC: Low-Watermark Mandatory Access Control v2.0.0\n");
+ return (error);
+ case MOD_UNLOAD:
+ /*
+ * It's always a bad idea to let a low-security process
+ * unload the module providing security.
+ */
+ if (initialized_procs &&
+ !mediate_subject_at_level("kldunload", curthread->td_proc,
+ LOMAC_HIGHEST_LEVEL))
+ return (EPERM);
+ /*
+ * Unloading doesn't work well at the moment...
+ */
+ return (EPERM);
+ if (initialized_sockets) {
+ error = lomac_uninitialize_sockets();
+ if (error)
+ break;
+ initialized_sockets = 0;
+ }
+ if (initialized_pipes) {
+ error = lomac_uninitialize_pipes();
+ if (error)
+ break;
+ initialized_pipes = 0;
+ }
+ if (initialized_syscalls) {
+ error = lomac_uninitialize_syscalls();
+ if (error)
+ break;
+ initialized_syscalls = 0;
+ }
+ if (initialized_procs) {
+ error = lomac_uninitialize_procs();
+ if (error)
+ break;
+ initialized_procs = 0;
+ }
+ if (initialized_vm) {
+ error = lomac_uninitialize_vm();
+ if (error)
+ break;
+ initialized_vm = 0;
+ }
+ if (lomac_dev) {
+ if (count_dev(lomac_dev) != 0)
+ return (EBUSY);
+ destroy_dev(lomac_dev);
+ }
+ printf("LOMAC: unloading\n");
+ linker_kernel_file = kernlf;
+ break;
+ case MOD_SHUTDOWN:
+ break;
+ }
+ return (0);
+}
+
+static moduledata_t lomac_moduledata = {
+ "lomac",
+ &lomac_modevent,
+ NULL
+};
+DECLARE_MODULE(lomac, lomac_moduledata, SI_SUB_VFS, SI_ORDER_ANY);
+MODULE_VERSION(lomac, 1);
+MODULE_DEPEND(lomac, syscall_gate, 1, 1, 1);
+MODULE_DEPEND(lomac, lomacfs, 1, 1, 1);
+MODULE_DEPEND(lomac, lomac_plm, 1, 1, 1);
diff --git a/sys/security/lomac/kernel_log.c b/sys/security/lomac/kernel_log.c
new file mode 100644
index 0000000..a43e70c
--- /dev/null
+++ b/sys/security/lomac/kernel_log.c
@@ -0,0 +1,199 @@
+/*-
+ * Copyright (c) 2001 Networks Associates Technologies, Inc.
+ * All rights reserved.
+ *
+ * This software was developed for the FreeBSD Project 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.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * 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.
+ *
+ * $Id$
+ * $FreeBSD$
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/module.h>
+#include <sys/sysctl.h>
+#include <sys/syslog.h>
+
+#include "lomacfs.h"
+
+#include "kernel_interface.h"
+
+/* The following definition sets the global log verbosity level. */
+SYSCTL_NODE(_kern, OID_AUTO, lomac, CTLFLAG_RW, 0, "LOMAC");
+SYSCTL_NODE(_kern_lomac, OID_AUTO, verbose, CTLFLAG_RW, 0, "LOMAC verbosity");
+#define VERBOSITY_SETTING(level) \
+ unsigned int lomac_verbose_##level## = 1; \
+ SYSCTL_UINT(_kern_lomac_verbose, OID_AUTO, level, \
+ CTLFLAG_RW, &lomac_verbose_##level##, 1, "")
+#include "kernel_log.h"
+
+/* sbuf_start()
+ *
+ * in: nothing
+ * out: nothing
+ * return: struct sbuf * to pass to later callers
+ *
+ */
+
+lomac_log_t *
+log_start(void) {
+ struct sbuf *s;
+
+ s = sbuf_new(NULL, NULL, PATH_MAX * 2, 0);
+ KASSERT(s != NULL, ("sbuf uses M_WAITOK -- must not return NULL!"));
+ return (s);
+} /* log_start() */
+
+
+/* log_append_string()
+ *
+ * in: s - a struct sbuf *
+ * in: data_s - null-terminated string to append to log
+ * out: nothing, see description for side-effects
+ * return: nothing
+ *
+ * This function appends `data_s' to `log_s', being careful to ensure
+ * that there is sufficient room in `log_s' for the data and a null
+ * terminator. If there is insufficient room in `log_s' for the entire
+ * `data_s' string, this function will append only the prefix of `data_s'
+ * which fits.
+ *
+ */
+
+void
+log_append_string(lomac_log_t *s, const char *data_s) {
+
+ (void)sbuf_cat(s, data_s);
+} /* log_append_string */
+
+
+/* log_append_int()
+ *
+ * in: data - integer value to append to log
+ * out: nothing, see description for side-effects
+ * return: nothing
+ *
+ * This function determines the ASCII representation of the integer
+ * value in `data' and, if there is sufficient room, appends this
+ * ASCII representation to `log_s'. If there is insufficient room,
+ * this function behaves as log_append_string().
+ *
+ */
+
+void
+log_append_int(lomac_log_t *s, int data) {
+
+ (void)sbuf_printf(s, "%d", data);
+} /* log_append_int() */
+
+
+/* log_append_subject_id()
+ *
+ * in: p_subject - subject whose ID we want to append to the log message
+ * out: nothing, see description for side-effects
+ * return: nothing
+ *
+ * This function appends a string describing the identity of `p_subject'
+ * to `log_s'. If there is insufficient room in `log_s' for the entire
+ * ID string, only a (possibly empty) prefix of the ID string will be
+ * appended.
+ *
+ */
+
+void
+log_append_subject_id(lomac_log_t *s, const lomac_subject_t *p_subject) {
+
+ (void)sbuf_printf(s, "p%dg%du%d:%s", p_subject->p_pid,
+ p_subject->p_pgrp->pg_id, p_subject->p_ucred->cr_uid,
+ p_subject->p_comm);
+} /* log_append_subject_id() */
+
+/* log_append_object_id()
+ *
+ * in: p_object - object whose ID we want to append to the log message
+ * out: nothing, see description for side-effects
+ * return: nothing
+ *
+ * This function appends a string describing the identity of `p_object'
+ * to `log_s'. If there is insufficient room in `log_s' for the entire
+ * ID string, only a (possibly empty) prefix of the ID string will be
+ * appended.
+ *
+ */
+
+void
+log_append_object_id(lomac_log_t *s, const lomac_object_t *p_object) {
+ struct lomac_node *ln;
+
+ switch (p_object->lo_type) {
+ case LO_TYPE_UVNODE:
+ (void)sbuf_printf(s, "vp %p", p_object->lo_object.vnode);
+ break;
+ case LO_TYPE_LVNODE:
+ ln = VTOLOMAC(p_object->lo_object.vnode);
+#ifdef LOMAC_DEBUG_INCNAME
+ (void)sbuf_printf(s, "named \"%s\"", ln->ln_name);
+#else
+ if (ln->ln_entry != NULL)
+ (void)sbuf_printf(s, "named \"%s\"",
+ ln->ln_entry->ln_path);
+ else
+ (void)sbuf_printf(s, "under \"%s\"",
+ ln->ln_underpolicy->ln_path);
+#endif
+ break;
+ case LO_TYPE_PIPE:
+ (void)sbuf_printf(s, "pipe %p", p_object->lo_object.pipe);
+ break;
+ case LO_TYPE_SOCKETPAIR:
+ (void)sbuf_printf(s, "socket %p", p_object->lo_object.socket);
+ break;
+ default:
+ panic("invalid LOMAC object type");
+ }
+} /* log_append_object_id() */
+
+/* log_print()
+ *
+ * in: nothing
+ * out: nothing
+ * return: nothing
+ *
+ * This function prints `log_s' to the system log.
+ *
+ */
+
+void
+log_print(lomac_log_t *s) {
+
+ sbuf_finish(s);
+ log(LOG_INFO, "%s", sbuf_data(s));
+ sbuf_delete(s);
+} /* log_print() */
diff --git a/sys/security/lomac/kernel_log.h b/sys/security/lomac/kernel_log.h
new file mode 100644
index 0000000..c88c124
--- /dev/null
+++ b/sys/security/lomac/kernel_log.h
@@ -0,0 +1,77 @@
+/*-
+ * Copyright (c) 2001 Networks Associates Technologies, Inc.
+ * All rights reserved.
+ *
+ * This software was developed for the FreeBSD Project 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.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * 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.
+ *
+ * $Id$
+ * $FreeBSD$
+ */
+
+#ifndef _KERNEL_LOG_H_
+#define _KERNEL_LOG_H_
+
+#include "kernel_interface.h"
+
+/* Use this unsigned int and its constants to set the log output *
+ * verbosity. Use of the log_* functions should be surrounded by *
+ * if statements of the form "if( verbose & VERBOSE_FOO )" where *
+ * VERBOSE_FOO is the constant below which corresponds to the *
+ * type of event you're logging. */
+#define VERBOSE_NOLOG 0x00000000 /* no log output, please. */
+#define VERBOSE_DEMOTE_DENY 0x00000001 /* log demotions and access denials. */
+#define VERBOSE_PIPE 0x00000002 /* log changes to pipe "levels". */
+#define VERBOSE_LOG_SOCKETS 0x00000004 /* log UNIX domain socket setup. */
+#define VERBOSE_LOG_OBJECTS 0x00000008 /* log opening of objects. */
+#ifdef TRUST
+#define VERBOSE_TRUST 0x00000020 /* log when trust stops demotion. */
+#endif
+
+#ifndef VERBOSITY_SETTING
+#define VERBOSITY_SETTING(level) extern unsigned int lomac_verbose_##level;
+#endif
+VERBOSITY_SETTING(demote_deny);
+VERBOSITY_SETTING(log_sockets);
+VERBOSITY_SETTING(log_objects);
+#ifdef LOMAC_DEBUG_PIPE
+VERBOSITY_SETTING(pipe);
+#endif
+#ifdef TRUST
+VERBOSITY_SETTING(trust);
+#endif
+
+lomac_log_t *log_start( void );
+void log_append_string( lomac_log_t *s, const char *data_s );
+void log_append_int( lomac_log_t *s, int data );
+void log_append_subject_id( lomac_log_t *s, const lomac_subject_t *p_subject );
+void log_append_object_id( lomac_log_t *s, const lomac_object_t *p_object );
+void log_print( lomac_log_t *s );
+
+#endif
diff --git a/sys/security/lomac/kernel_mediate.c b/sys/security/lomac/kernel_mediate.c
new file mode 100644
index 0000000..472dea6
--- /dev/null
+++ b/sys/security/lomac/kernel_mediate.c
@@ -0,0 +1,289 @@
+/*-
+ * Copyright (c) 2001 Networks Associates Technologies, Inc.
+ * All rights reserved.
+ *
+ * This software was developed for the FreeBSD Project 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.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * 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.
+ *
+ * $Id$
+ * $FreeBSD$
+ */
+
+/*
+ * This file contains functions that make access control decisions
+ * concerning wether or not given system calls should be allowed
+ * or denied. This activity is called "mediation". These functions
+ * generally consider both the parameters passed to a system call
+ * and the current internal state of LOMAC in the course of making
+ * a decision. However, they do not modify these parameters or
+ * LOMAC's internal state. Functions for modifying LOMAC's internal
+ * state can be found in lomac_monitor.c.
+ *
+ */
+
+#include "kernel_interface.h"
+#include "kernel_mediate.h"
+#if 0
+#include "lomac_plm.h"
+#endif
+#include "kernel_log.h"
+
+/* mediate_subject_level_subject()
+ *
+ * in: op_s - name of operation to mediate
+ * p_subject_one - subject one (for informational purposes only)
+ * level_one - already-known level of the first subject
+ * p_subject_two - subject two
+ * out: nothing
+ * return: value condition
+ * ----- ---------
+ * 0 caller should deny operation
+ * 1 caller should allow operation
+ *
+ * This function returns 1 if `p_subject_one's level is at least
+ * as great as `p_subject_two's level. Otherwise, it logs a permission
+ * failure on operation `op_s' and returns 0.
+ *
+ * This function is used to mediate pgrp changes.
+ *
+ */
+
+int
+mediate_subject_level_subject(const char *op_s,
+ const lomac_subject_t *p_subject_one, level_t level_one,
+ lomac_subject_t *p_subject_two) {
+
+ lattr_t lattr_two; /* lattr of `p_subject_two' */
+ int ret_val; /* result to return to caller */
+
+#ifdef NO_MEDIATION
+ ret_val = 1; /* no denials, just logging */
+#else
+ ret_val = 0; /* pessimistically assume deny */
+#endif
+
+ get_subject_lattr(p_subject_two, &lattr_two);
+
+ if (lattr_two.level <= level_one) {
+ ret_val = 1; /* OK, allow */
+ } else if (lomac_verbose_demote_deny) {
+ lomac_log_t *logmsg = log_start();
+
+ log_append_string(logmsg, "LOMAC: denied level-");
+ log_append_int(logmsg, level_one);
+ log_append_string(logmsg, " proc ");
+ log_append_subject_id(logmsg, p_subject_one);
+ log_append_string(logmsg, " ");
+ log_append_string(logmsg, op_s);
+ log_append_string(logmsg, " to level-");
+ log_append_int(logmsg, lattr_two.level);
+ log_append_string(logmsg, " proc ");
+ log_append_subject_id(logmsg, p_subject_two);
+ log_print(logmsg);
+ }
+ return (ret_val);
+} /* mediate_subject_subject() */
+
+/* mediate_subject_object()
+ *
+ * in: op_s - string describing operation, like "write" or "writev"
+ * p_subject - subject trying to operate on `p_object'.
+ * p_object - object that `p_subject' is trying to operate on.
+ * out: nothing
+ * return: value condition
+ * ----- ---------
+ * 0 Caller should prevent operation
+ * 1 Caller should permit operation
+ *
+ * This function returns 1 if the level of `p_object' is less than or
+ * equal to the level of `p_subject'. Otherwise, it returns 0 and
+ * logs a permission denial on `op_s'.
+ *
+ * This function allows LOMAC to mediate write and writev system calls.
+ *
+ */
+
+int
+mediate_subject_object(const char *op_s, lomac_subject_t *p_subject,
+ const lomac_object_t *p_object) {
+ lattr_t subject_lattr; /* lattr of `p_subject' */
+ lattr_t object_lattr; /* lattr of `p_object' */
+ int ret_val; /* value to return to caller */
+
+#ifdef NO_MEDIATION
+ ret_val = 1; /* allow operation regardless of decision */
+#else
+ ret_val = 0; /* pessimistically assume deny */
+#endif
+
+ /* Get the lattrs of `p_subject' and `p_object' so we can compare them. */
+ get_subject_lattr(p_subject, &subject_lattr);
+ get_object_lattr(p_object, &object_lattr);
+
+ /*
+ * If `p_subject's level is less than `p_object's level,
+ * we indicate that the operation must not be allowed.
+ */
+
+ if (!lomac_must_deny(&subject_lattr, &object_lattr) ||
+ object_lattr.flags & LOMAC_ATTR_LOWWRITE) {
+ ret_val = 1; /* allow operation */
+ } else if (lomac_verbose_demote_deny) {
+ lomac_log_t *logmsg = log_start();
+ log_append_string(logmsg, "LOMAC: level-");
+ log_append_int(logmsg, subject_lattr.level);
+ log_append_string(logmsg, " proc ");
+ log_append_subject_id(logmsg, p_subject);
+ log_append_string(logmsg, " denied ");
+ log_append_string(logmsg, op_s);
+ log_append_string(logmsg, " to level-");
+ log_append_int(logmsg, object_lattr.level);
+ log_append_string(logmsg, " object ");
+ log_append_object_id(logmsg, p_object);
+ log_append_string(logmsg, "\n");
+ log_print(logmsg);
+ }
+ return (ret_val);
+} /* mediate_subject_object() */
+
+
+/* mediate_subject_object_open()
+ *
+ * in: p_subject - subject trying to operate on `p_object'.
+ * p_object - object that `p_subject' is trying to operate on.
+ * out: nothing
+ * return: value condition
+ * ----- ---------
+ * 0 Caller should prevent operation
+ * 1 Caller should permit operation
+ *
+ * This function returns 1 if the level of `p_object' is less than or
+ * equal to the level of `p_subject'. Otherwise, it returns 0 and
+ * logs a permission denial on `op_s'.
+ *
+ * This function allows LOMAC to mediate open system calls.
+ *
+ */
+
+int
+mediate_subject_object_open(lomac_subject_t *p_subject,
+ const lomac_object_t *p_object) {
+ lattr_t subject_lattr; /* lattr of `p_subject' */
+ lattr_t object_lattr; /* lattr of `p_object' */
+ int ret_val; /* value to return to caller */
+
+#ifdef NO_MEDIATION
+ ret_val = 1; /* allow operation regardless of decision */
+#else
+ ret_val = 0; /* pessimistically assume deny */
+#endif
+
+ /* Get the lattrs of `p_subject' and `p_object' so we can compare them. */
+ get_subject_lattr(p_subject, &subject_lattr);
+ get_object_lattr(p_object, &object_lattr);
+
+ /*
+ * If `p_subject's level is less than `p_object's level,
+ * we must indicate that the operation should not be allowed.
+ */
+ if (lomac_must_deny(&subject_lattr, &object_lattr) &&
+ object_lattr.flags & LOMAC_ATTR_LOWNOOPEN) {
+ if (lomac_verbose_demote_deny) {
+ lomac_log_t *logmsg = log_start();
+
+ log_append_string(logmsg, "LOMAC: level-");
+ log_append_int(logmsg, subject_lattr.level);
+ log_append_string(logmsg, " proc ");
+ log_append_subject_id(logmsg, p_subject);
+ log_append_string(logmsg, " denied open to level-");
+ log_append_int(logmsg, object_lattr.level);
+ log_append_string(logmsg, " object ");
+ log_append_object_id(logmsg, p_object);
+ log_append_string(logmsg, "\n");
+ log_print(logmsg);
+ }
+ } else {
+ ret_val = 1; /* allow operation */
+ } /* if/else allow/deny */
+ return (ret_val);
+} /* mediate_subject_object() */
+
+
+/* mediate_subject_at_level()
+ *
+ * in: op_s - name of operation being mediated
+ * p_subject - subject whose level we want to check
+ * target_level - level to compare to `p_subject's level
+ *
+ * out: nothing
+ * return: value condition
+ * ----- ---------
+ * 0 `p_subject' is not at `target_level'
+ * 1 `p_subject' is at `target_level'
+ *
+ * This function provides a predicate for determining whether or not
+ * `p_subject' is at the level specified by `target_level'. This
+ * function compares `p_subject's level to `target_level'. If the
+ * levels match, it retruns 1. Otherwise, it logs a permission denial
+ * on `op_s' and returns 0.
+ *
+ */
+
+int
+mediate_subject_at_level(const char *op_s, lomac_subject_t *p_subject,
+ const level_t target_level) {
+ lattr_t subject_lattr; /* lattr of `p_subject' */
+ int ret_val; /* value returned to caller */
+
+#ifdef NO_MEDIATION
+ ret_val = 1; /* allow operation regardless of decision */
+#else
+ ret_val = 0; /* pessimistically assume deny */
+#endif
+
+ /* Make `subject_lattr' the lattr of `p_subject'. */
+ get_subject_lattr(p_subject, &subject_lattr);
+
+ /* compare with `target_lattr */
+ if (subject_lattr.level == target_level) {
+ ret_val = 1; /* allow operation */
+ } else if (lomac_verbose_demote_deny) {
+ lomac_log_t *logmsg = log_start();
+
+ log_append_string(logmsg, "LOMAC: denied level-");
+ log_append_int(logmsg, subject_lattr.level);
+ log_append_string(logmsg, " proc ");
+ log_append_subject_id(logmsg, p_subject);
+ log_append_string(logmsg, "'s ");
+ log_append_string(logmsg, op_s);
+ log_append_string(logmsg, ".\n");
+ log_print(logmsg);
+ }
+ return (ret_val);
+} /* mediate_subject_at_level() */
diff --git a/sys/security/lomac/kernel_mediate.h b/sys/security/lomac/kernel_mediate.h
new file mode 100644
index 0000000..23c24e2
--- /dev/null
+++ b/sys/security/lomac/kernel_mediate.h
@@ -0,0 +1,68 @@
+/*-
+ * Copyright (c) 2001 Networks Associates Technologies, Inc.
+ * All rights reserved.
+ *
+ * This software was developed for the FreeBSD Project 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.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * 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.
+ *
+ * $Id$
+ * $FreeBSD$
+ */
+
+#ifndef _KERNEL_MEDIATE_H_
+#define _KERNEL_MEDIATE_H_
+
+#include "kernel_interface.h"
+
+int mediate_subject_level_subject( const char *op_s,
+ const lomac_subject_t *p_subject_one,
+ level_t level_one,
+ lomac_subject_t *p_subject_two );
+int mediate_subject_object( const char *op_s, lomac_subject_t *p_subject,
+ const lomac_object_t *p_object );
+int mediate_subject_object_open( lomac_subject_t *p_subject,
+ const lomac_object_t *p_object );
+#if 0
+int mediate_subject_path( const char *op_s, const lomac_subject_t *p_subject,
+ const char *path_s );
+int mediate_path_path( const char *op_s, const lomac_subject_t *p_subject,
+ const char *canabsname_one_s,
+ const char *canabsname_two_s );
+#endif
+int mediate_subject_at_level( const char *op_s,
+ lomac_subject_t *p_subject,
+ const level_t target_level );
+#if 0
+int mediate_object_at_level( const char *op_s,
+ const lomac_subject_t *p_subject,
+ const lomac_object_t *p_object,
+ const level_t target_level );
+#endif
+
+#endif
diff --git a/sys/security/lomac/kernel_mmap.c b/sys/security/lomac/kernel_mmap.c
new file mode 100644
index 0000000..cc91383
--- /dev/null
+++ b/sys/security/lomac/kernel_mmap.c
@@ -0,0 +1,553 @@
+/*-
+ * Copyright (c) 2001 Networks Associates Technologies, Inc.
+ * Copyright (c) 1988 University of Utah.
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed for the FreeBSD Project 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.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * 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.
+ *
+ * @(#)vm_mmap.c 8.4 (Berkeley) 1/12/94
+ * $FreeBSD$
+ * $Id$
+ * $FreeBSD$
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/sysproto.h>
+#include <sys/filedesc.h>
+#include <sys/proc.h>
+#include <sys/vnode.h>
+#include <sys/file.h>
+#include <sys/fcntl.h>
+#include <sys/conf.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+
+#include <vm/vm.h>
+#include <vm/vm_extern.h>
+#include <vm/vm_param.h>
+#include <vm/pmap.h>
+#include <vm/vm_map.h>
+#include <vm/vm_object.h>
+#include <vm/vm_page.h>
+#include <vm/vm_pager.h>
+
+#include "kernel_interface.h"
+#include "kernel_mediate.h"
+#include "kernel_monitor.h"
+#include "kernel_util.h"
+#include "lomacfs.h"
+
+extern int max_proc_mmap;
+
+int lomac_mmap(struct proc *, struct mmap_args *);
+
+/*
+ * Memory Map (mmap) system call. Note that the file offset
+ * and address are allowed to be NOT page aligned, though if
+ * the MAP_FIXED flag it set, both must have the same remainder
+ * modulo the PAGE_SIZE (POSIX 1003.1b). If the address is not
+ * page-aligned, the actual mapping starts at trunc_page(addr)
+ * and the return value is adjusted up by the page offset.
+ *
+ * Generally speaking, only character devices which are themselves
+ * memory-based, such as a video framebuffer, can be mmap'd. Otherwise
+ * there would be no cache coherency between a descriptor and a VM mapping
+ * both to the same character device.
+ *
+ * Block devices can be mmap'd no matter what they represent. Cache coherency
+ * is maintained as long as you do not write directly to the underlying
+ * character device.
+ */
+#ifndef _SYS_SYSPROTO_H_
+struct mmap_args {
+ void *addr;
+ size_t len;
+ int prot;
+ int flags;
+ int fd;
+ long pad;
+ off_t pos;
+};
+#endif
+
+int
+mmap(td, uap)
+ struct thread *td;
+ struct mmap_args *uap;
+{
+ struct proc *p = td->td_proc;
+ struct filedesc *fdp = p->p_fd;
+ struct file *fp = NULL;
+ struct vnode *vp, *origvp;
+ vm_offset_t addr;
+ vm_size_t size, pageoff;
+ vm_prot_t prot, maxprot;
+ void *handle;
+ int flags, error;
+ int disablexworkaround;
+ off_t pos;
+ struct vmspace *vms = p->p_vmspace;
+ vm_object_t obj;
+ lomac_object_t lobj;
+
+ addr = (vm_offset_t) uap->addr;
+ size = uap->len;
+ prot = uap->prot & VM_PROT_ALL;
+ flags = uap->flags;
+ pos = uap->pos;
+ origvp = NULL;
+
+ /* make sure mapping fits into numeric range etc */
+ if ((ssize_t) uap->len < 0 ||
+ ((flags & MAP_ANON) && uap->fd != -1))
+ return (EINVAL);
+
+ if (flags & MAP_STACK) {
+ if ((uap->fd != -1) ||
+ ((prot & (PROT_READ | PROT_WRITE)) != (PROT_READ | PROT_WRITE)))
+ return (EINVAL);
+ flags |= MAP_ANON;
+ pos = 0;
+ }
+
+ /*
+ * Align the file position to a page boundary,
+ * and save its page offset component.
+ */
+ pageoff = (pos & PAGE_MASK);
+ pos -= pageoff;
+
+ /* Adjust size for rounding (on both ends). */
+ size += pageoff; /* low end... */
+ size = (vm_size_t) round_page(size); /* hi end */
+
+ /*
+ * Check for illegal addresses. Watch out for address wrap... Note
+ * that VM_*_ADDRESS are not constants due to casts (argh).
+ */
+ if (flags & MAP_FIXED) {
+ /*
+ * The specified address must have the same remainder
+ * as the file offset taken modulo PAGE_SIZE, so it
+ * should be aligned after adjustment by pageoff.
+ */
+ addr -= pageoff;
+ if (addr & PAGE_MASK)
+ return (EINVAL);
+ /* Address range must be all in user VM space. */
+ if (VM_MAXUSER_ADDRESS > 0 && addr + size > VM_MAXUSER_ADDRESS)
+ return (EINVAL);
+#ifndef i386
+ if (VM_MIN_ADDRESS > 0 && addr < VM_MIN_ADDRESS)
+ return (EINVAL);
+#endif
+ if (addr + size < addr)
+ return (EINVAL);
+ }
+ /*
+ * XXX for non-fixed mappings where no hint is provided or
+ * the hint would fall in the potential heap space,
+ * place it after the end of the largest possible heap.
+ *
+ * There should really be a pmap call to determine a reasonable
+ * location.
+ */
+ else if (addr == 0 ||
+ (addr >= round_page((vm_offset_t)vms->vm_taddr) &&
+ addr < round_page((vm_offset_t)vms->vm_daddr + MAXDSIZ)))
+ addr = round_page((vm_offset_t)vms->vm_daddr + MAXDSIZ);
+
+ mtx_lock(&Giant); /* syscall marked mp-safe but isn't */
+ if (flags & MAP_ANON) {
+ /*
+ * Mapping blank space is trivial.
+ */
+ handle = NULL;
+ maxprot = VM_PROT_ALL;
+ pos = 0;
+ } else {
+ /*
+ * Mapping file, get fp for validation. Obtain vnode and make
+ * sure it is of appropriate type.
+ */
+ if (((unsigned) uap->fd) >= fdp->fd_nfiles ||
+ (fp = fdp->fd_ofiles[uap->fd]) == NULL) {
+ mtx_unlock(&Giant);
+ return (EBADF);
+ }
+ if (fp->f_type != DTYPE_VNODE) {
+ mtx_unlock(&Giant);
+ return (EINVAL);
+ }
+
+ /*
+ * don't let the descriptor disappear on us if we block
+ */
+ fhold(fp);
+
+ /*
+ * POSIX shared-memory objects are defined to have
+ * kernel persistence, and are not defined to support
+ * read(2)/write(2) -- or even open(2). Thus, we can
+ * use MAP_ASYNC to trade on-disk coherence for speed.
+ * The shm_open(3) library routine turns on the FPOSIXSHM
+ * flag to request this behavior.
+ */
+ if (fp->f_flag & FPOSIXSHM)
+ flags |= MAP_NOSYNC;
+ vp = (struct vnode *) fp->f_data;
+ if (vp->v_type != VREG && vp->v_type != VCHR) {
+ error = EINVAL;
+ goto done;
+ }
+ if (vp->v_type == VREG) {
+ /*
+ * Get the proper underlying object
+ */
+ if (VOP_GETVOBJECT(vp, &obj) != 0) {
+ error = EINVAL;
+ goto done;
+ }
+ origvp = vp;
+ vp = (struct vnode*)obj->handle;
+ }
+ /*
+ * XXX hack to handle use of /dev/zero to map anon memory (ala
+ * SunOS).
+ */
+ if ((vp->v_type == VCHR) &&
+ (vp->v_rdev->si_devsw->d_flags & D_MMAP_ANON)) {
+ handle = NULL;
+ maxprot = VM_PROT_ALL;
+ flags |= MAP_ANON;
+ pos = 0;
+ } else {
+ /*
+ * cdevs does not provide private mappings of any kind.
+ */
+ /*
+ * However, for XIG X server to continue to work,
+ * we should allow the superuser to do it anyway.
+ * We only allow it at securelevel < 1.
+ * (Because the XIG X server writes directly to video
+ * memory via /dev/mem, it should never work at any
+ * other securelevel.
+ * XXX this will have to go
+ */
+ if (securelevel >= 1)
+ disablexworkaround = 1;
+ else
+ disablexworkaround = suser(p);
+ if (vp->v_type == VCHR && disablexworkaround &&
+ (flags & (MAP_PRIVATE|MAP_COPY))) {
+ error = EINVAL;
+ goto done;
+ }
+ /*
+ * Ensure that file and memory protections are
+ * compatible. Note that we only worry about
+ * writability if mapping is shared; in this case,
+ * current and max prot are dictated by the open file.
+ * XXX use the vnode instead? Problem is: what
+ * credentials do we use for determination? What if
+ * proc does a setuid?
+ */
+ maxprot = VM_PROT_EXECUTE; /* ??? */
+ if (fp->f_flag & FREAD) {
+ maxprot |= VM_PROT_READ;
+ } else if (prot & PROT_READ) {
+ error = EACCES;
+ goto done;
+ }
+ /*
+ * If we are sharing potential changes (either via
+ * MAP_SHARED or via the implicit sharing of character
+ * device mappings), and we are trying to get write
+ * permission although we opened it without asking
+ * for it, bail out. Check for superuser, only if
+ * we're at securelevel < 1, to allow the XIG X server
+ * to continue to work.
+ */
+
+ if ((flags & MAP_SHARED) != 0 ||
+ (vp->v_type == VCHR && disablexworkaround)) {
+ if ((fp->f_flag & FWRITE) != 0) {
+ struct vattr va;
+ if ((error =
+ VOP_GETATTR(vp, &va,
+ p->p_ucred, td))) {
+ goto done;
+ }
+ if ((va.va_flags &
+ (SF_SNAPSHOT|IMMUTABLE|APPEND)) == 0) {
+ maxprot |= VM_PROT_WRITE;
+ } else if (prot & PROT_WRITE) {
+ error = EPERM;
+ goto done;
+ }
+ } else if ((prot & PROT_WRITE) != 0) {
+ error = EACCES;
+ goto done;
+ }
+ } else {
+ maxprot |= VM_PROT_WRITE;
+ }
+
+ handle = (void *)vp;
+ origvp = vp;
+ }
+ }
+
+ /*
+ * Do not allow more then a certain number of vm_map_entry structures
+ * per process. Scale with the number of rforks sharing the map
+ * to make the limit reasonable for threads.
+ */
+ if (max_proc_mmap &&
+ vms->vm_map.nentries >= max_proc_mmap * vms->vm_refcnt) {
+ error = ENOMEM;
+ goto done;
+ }
+
+ mtx_unlock(&Giant);
+ error = 0;
+ if (handle != NULL && VISLOMAC(origvp)) {
+ lobj.lo_type = LO_TYPE_LVNODE;
+ lobj.lo_object.vnode = origvp;
+ if (flags & MAP_SHARED && maxprot & VM_PROT_WRITE &&
+ !mediate_subject_object("mmap", p, &lobj))
+ error = EPERM;
+ if (error == 0 && maxprot & VM_PROT_READ)
+ error = monitor_read_object(p, &lobj);
+ }
+ if (error == 0)
+ error = vm_mmap(&vms->vm_map, &addr, size, prot, maxprot,
+ flags, handle, pos);
+ if (error == 0)
+ td->td_retval[0] = (register_t) (addr + pageoff);
+ mtx_lock(&Giant);
+done:
+ if (fp)
+ fdrop(fp, td);
+ mtx_unlock(&Giant);
+ return (error);
+}
+
+static void
+vm_drop_perms_recurse(struct thread *td, struct vm_map *map, lattr_t *lattr) {
+ struct vm_map_entry *vme;
+
+ for (vme = map->header.next; vme != &map->header; vme = vme->next) {
+ if (vme->eflags & MAP_ENTRY_IS_SUB_MAP) {
+ vm_map_lock_read(vme->object.sub_map);
+ vm_drop_perms_recurse(td, vme->object.sub_map,
+ lattr);
+ vm_map_unlock_read(vme->object.sub_map);
+ continue;
+ }
+ if ((vme->eflags & (MAP_ENTRY_COW | MAP_ENTRY_NOSYNC)) == 0 &&
+ vme->max_protection & VM_PROT_WRITE) {
+ vm_object_t object;
+ vm_ooffset_t offset;
+ lomac_object_t lobj;
+ struct vnode *vp;
+ lattr_t olattr;
+
+ offset = vme->offset;
+ object = vme->object.vm_object;
+ if (object == NULL)
+ continue;
+ while (object->backing_object) {
+ object = object->backing_object;
+ offset += object->backing_object_offset;
+ }
+ /*
+ * Regular objects (swap, etc.) inherit from
+ * their creator. Vnodes inherit from their
+ * underlying on-disk object.
+ */
+ if (object->type == OBJT_DEVICE)
+ continue;
+ if (object->type == OBJT_VNODE) {
+ vp = lobj.lo_object.vnode = object->handle;
+ /*
+ * For the foreseeable future, an OBJT_VNODE
+ * is always !VISLOMAC().
+ */
+ lobj.lo_type = VISLOMAC(vp) ?
+ LO_TYPE_LVNODE : LO_TYPE_UVNODE;
+ } else {
+ vp = NULL;
+ lobj.lo_object.vm_object = object;
+ lobj.lo_type = LO_TYPE_VM_OBJECT;
+ }
+ get_object_lattr(&lobj, &olattr);
+ /*
+ * Revoke write access only to files with a higher
+ * level than the process or which have a possibly-
+ * undeterminable level (interpreted as "lowest").
+ */
+ if (lomac_must_deny(lattr, &olattr))
+ continue;
+ vm_map_lock_upgrade(map);
+ /*
+ * If it's a private, non-file-backed mapping and
+ * not mapped anywhere else, we can just take it
+ * down with us.
+ */
+ if (vp == NULL && object->flags & OBJ_ONEMAPPING) {
+ olattr.level = lattr->level;
+ set_object_lattr(&lobj, olattr);
+ goto downgrade;
+ }
+ if ((vme->protection & VM_PROT_WRITE) == 0)
+ vme->max_protection &= ~VM_PROT_WRITE;
+ else {
+ vm_object_reference(object);
+ if (vp != NULL)
+ vn_lock(vp, LK_EXCLUSIVE | LK_RETRY,
+ td);
+ vm_object_page_clean(object,
+ OFF_TO_IDX(offset),
+ OFF_TO_IDX(offset + vme->end - vme->start +
+ PAGE_MASK),
+ OBJPC_SYNC);
+ if (vp != NULL)
+ VOP_UNLOCK(vp, 0, td);
+ vm_object_deallocate(object);
+ vme->eflags |= MAP_ENTRY_COW |
+ MAP_ENTRY_NEEDS_COPY;
+ pmap_protect(map->pmap, vme->start, vme->end,
+ vme->protection & ~VM_PROT_WRITE);
+ vm_map_simplify_entry(map, vme);
+ }
+ downgrade:
+ vm_map_lock_downgrade(map);
+ }
+ }
+}
+
+void
+kernel_vm_drop_perms(struct thread *td, lattr_t *newlattr) {
+ struct vm_map *map = &td->td_proc->p_vmspace->vm_map;
+
+ mtx_lock(&Giant);
+ vm_map_lock_read(map);
+ vm_drop_perms_recurse(td, map, newlattr);
+ vm_map_unlock_read(map);
+ mtx_unlock(&Giant);
+}
+
+/*
+ * Take the level of new vm_objects from the parent subject's level.
+ */
+static void
+vm_object_init_lattr(vm_object_t object) {
+ lomac_object_t lobj;
+ lattr_t lattr;
+
+ get_subject_lattr(curthread->td_proc, &lattr);
+ lattr.flags = 0;
+ lobj.lo_type = LO_TYPE_VM_OBJECT;
+ lobj.lo_object.vm_object = object;
+ set_object_lattr(&lobj, lattr);
+}
+
+
+#define PGO_ALLOC_REPLACEMENT(n) \
+static vm_object_t (*old_pgo_alloc_##n)(void *, vm_ooffset_t, \
+ vm_prot_t, vm_ooffset_t); \
+ \
+static vm_object_t \
+pgo_alloc_##n(void *handle, vm_ooffset_t size, vm_prot_t prot, \
+ vm_ooffset_t off) { \
+ vm_object_t newobj = NULL; \
+ \
+ newobj = old_pgo_alloc_##n(handle, size, prot, off); \
+ if (newobj != NULL) \
+ vm_object_init_lattr(newobj); \
+ return (newobj); \
+}
+
+#define PGO_ALLOC_REPLACE(n) \
+ do { \
+ old_pgo_alloc_##n = pagertab[n]->pgo_alloc; \
+ if (pagertab[n]->pgo_alloc != NULL) \
+ pagertab[n]->pgo_alloc = pgo_alloc_##n; \
+ } while (0)
+
+#define PGO_ALLOC_UNREPLACE(n) \
+ do { \
+ pagertab[n]->pgo_alloc = old_pgo_alloc_##n; \
+ } while (0)
+
+PGO_ALLOC_REPLACEMENT(0);
+PGO_ALLOC_REPLACEMENT(1);
+PGO_ALLOC_REPLACEMENT(2);
+PGO_ALLOC_REPLACEMENT(3);
+PGO_ALLOC_REPLACEMENT(4);
+PGO_ALLOC_REPLACEMENT(5);
+
+extern int npagers;
+
+int
+lomac_initialize_vm(void) {
+ GIANT_REQUIRED;
+
+ if (npagers != 6) {
+ printf("LOMAC: number of pagers %d not expected 6!\n", npagers);
+ return (EDOM);
+ }
+ PGO_ALLOC_REPLACE(0);
+ PGO_ALLOC_REPLACE(1);
+ PGO_ALLOC_REPLACE(2);
+ PGO_ALLOC_REPLACE(3);
+ PGO_ALLOC_REPLACE(4);
+ PGO_ALLOC_REPLACE(5);
+ return (0);
+}
+
+int
+lomac_uninitialize_vm(void) {
+ GIANT_REQUIRED;
+
+ PGO_ALLOC_UNREPLACE(0);
+ PGO_ALLOC_UNREPLACE(1);
+ PGO_ALLOC_UNREPLACE(2);
+ PGO_ALLOC_UNREPLACE(3);
+ PGO_ALLOC_UNREPLACE(4);
+ PGO_ALLOC_UNREPLACE(5);
+ return (0);
+}
diff --git a/sys/security/lomac/kernel_monitor.c b/sys/security/lomac/kernel_monitor.c
new file mode 100644
index 0000000..3568680
--- /dev/null
+++ b/sys/security/lomac/kernel_monitor.c
@@ -0,0 +1,206 @@
+/*-
+ * Copyright (c) 2001 Networks Associates Technologies, Inc.
+ * All rights reserved.
+ *
+ * This software was developed for the FreeBSD Project 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.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * 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.
+ *
+ * $Id$
+ * $FreeBSD$
+ */
+
+/*
+ * This file contains functions which update LOMAC's internal
+ * state in response to system events, such as successful
+ * system calls. These updates allow LOMAC to keep an accurate
+ * picture of the kernel's state, enabling LOMAC to make reasonable
+ * decisions when it mediates processes' use of security-relevant
+ * system calls. These functions perform no mediation themselves -
+ * that is, they do not make access control decisions concerning
+ * whether a given system call should be allowed or denied. This
+ * mediation is handled by the functions in lomac_mediate.c.
+ */
+
+#include "kernel_interface.h"
+#include "kernel_monitor.h"
+#include "kernel_log.h"
+
+#include "kernel_util.h"
+
+
+/* monitor_read_object()
+ *
+ * in: p_subject - subject that read `p_object'.
+ * p_object - object read by `p_subject'.
+ * out: nothing
+ * return: nothing
+ *
+ * This function examines the objects read by subjects. If a subject
+ * reads from an object with a level lower than its own, this function
+ * reduces the subject's level to match the object's. This lowering
+ * is referred to as "demotion" in much of the LOMAC documentation.
+ * This function performs no mediation.
+ *
+ * This function is for the following kinds of objects:
+ * regular files and FIFOs.
+ * It is also used to monitor reads on unnamed pipes. LOMAC does not
+ * consider unnamed pipes to be objects, and treats them differently
+ * from objects such as files. However, the differences are mostly
+ * in the write-handling behavior. LOMAC's read-handling behavior is
+ * the same both for objects and unnamed pipes, so this function
+ * handles both cases.
+ */
+
+int
+monitor_read_object(lomac_subject_t *p_subject, lomac_object_t *p_object) {
+ lattr_t subject_lattr; /* lattr of `p_subject' */
+ lattr_t object_lattr; /* lattr of `p_object' */
+
+ /* Get the lattrs of `p_subject' and `p_object' so we can compare them. */
+ get_subject_lattr(p_subject, &subject_lattr);
+ get_object_lattr(p_object, &object_lattr);
+
+ /*
+ * If `p_object's level is less than `p_subject's level,
+ * we must demote `p_subject'. The level may be 0 to indicate
+ * existence before LOMAC started.
+ */
+ if (object_lattr.level &&
+ lomac_must_demote(&subject_lattr, &object_lattr) &&
+ (subject_lattr.flags & LOMAC_ATTR_NODEMOTE) == 0) {
+ if (subject_do_not_demote(p_subject))
+ return (0);
+ set_subject_lattr(p_subject, object_lattr); /* demote! */
+ if (lomac_verbose_demote_deny) {
+ lomac_log_t *s = log_start();
+
+ log_append_string(s, "LOMAC: level-");
+ log_append_int(s, subject_lattr.level);
+ log_append_string(s, " subject ");
+ log_append_subject_id(s, p_subject);
+ log_append_string(s, " demoted to level ");
+ log_append_int(s, object_lattr.level);
+ log_append_string(s, " after reading ");
+ log_append_object_id(s, p_object);
+ log_append_string(s, "\n");
+ log_print(s);
+ }
+ } /* if we need to demote */
+ return (0);
+} /* monitor_read_object() */
+
+
+/* monitor_pipe_write()
+ *
+ * in: p_subject - subject that just wrote to `p_pipe'.
+ * p_pipe - pipe `p_subject' has written to.
+ * out: p_pipe - pipe may have its level adjusted.
+ * return: 0
+ *
+ * This function should be called after a successful write to
+ * `p_pipe'. If the level of `p_subject' is less than the level of
+ * `p_pipe', this function reduces `p_pipe's level to match
+ * `current's.
+ *
+ *
+ */
+
+int
+monitor_pipe_write(lomac_subject_t *p_subject, lomac_object_t *p_pipe) {
+ lattr_t pipe_lattr; /* lattr of `p_pipe' */
+ lattr_t subject_lattr; /* lattr of `p_subject' */
+
+ get_subject_lattr(p_subject, &subject_lattr);
+ get_object_lattr(p_pipe, &pipe_lattr);
+ if (lomac_must_demote(&pipe_lattr, &subject_lattr)) {
+ subject_lattr.flags = 0;
+ set_object_lattr(p_pipe, subject_lattr);
+#ifdef LOMAC_DEBUG_PIPE
+ if (lomac_verbose_pipe) {
+ lomac_log_t *s = log_start();
+
+ log_append_string(s, "LOMAC: level-");
+ log_append_int(s, subject_lattr.level);
+ log_append_string(s, " subject ");
+ log_append_subject_id(s, p_subject);
+ log_append_string(s, " contaminated level-");
+ log_append_int(s, pipe_lattr.level);
+ log_append_string(s, " ");
+ log_append_object_id(s, p_pipe);
+ log_append_string(s, "\n");
+ log_print(s);
+ }
+#endif /* LOMAC_DEBUG_PIPE */
+ }
+ return (0);
+} /* monitor_pipe_write() */
+
+
+/* monitor_read_net_socket()
+ *
+ * in: p_subject - subject that read from network socket.
+ * out: nothing
+ * return: 0
+ *
+ *
+ */
+
+int
+monitor_read_net_socket(lomac_subject_t *p_subject) {
+ lattr_t subject_lattr; /* lattr of `p_subject' */
+ lattr_t socket_lattr; /* lattr of socket (always lowest) */
+
+ socket_lattr.level = LOMAC_LOWEST_LEVEL;
+ socket_lattr.flags = 0;
+ get_subject_lattr(p_subject, &subject_lattr);
+
+ if (lomac_must_demote(&subject_lattr, &socket_lattr) &&
+ (subject_lattr.flags &
+ (LOMAC_ATTR_NODEMOTE | LOMAC_ATTR_NONETDEMOTE)) == 0) {
+
+ if (subject_do_not_demote(p_subject))
+ return (0);
+ socket_lattr.flags = subject_lattr.flags;
+ set_subject_lattr(p_subject, socket_lattr); /* demote! */
+ if (lomac_verbose_demote_deny) {
+ lomac_log_t *s = log_start();
+
+ log_append_string(s, "LOMAC: level-");
+ log_append_int(s, subject_lattr.level);
+ log_append_string(s, " subject ");
+ log_append_subject_id(s, p_subject);
+ log_append_string(s, " demoted to level ");
+ log_append_int(s, socket_lattr.level);
+ log_append_string(s, " after reading from "
+ "the network\n");
+ log_print(s);
+ }
+ }
+ return (0);
+}
diff --git a/sys/security/lomac/kernel_monitor.h b/sys/security/lomac/kernel_monitor.h
new file mode 100644
index 0000000..a429465
--- /dev/null
+++ b/sys/security/lomac/kernel_monitor.h
@@ -0,0 +1,62 @@
+/*-
+ * Copyright (c) 2001 Networks Associates Technologies, Inc.
+ * All rights reserved.
+ *
+ * This software was developed for the FreeBSD Project 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.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * 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.
+ *
+ * $Id$
+ * $FreeBSD$
+ */
+
+#ifndef _LOMAC_MONITOR_H_
+#define _LOMAC_MONITOR_H_
+
+int monitor_read_object( lomac_subject_t *, lomac_object_t * );
+int monitor_pipe_write( lomac_subject_t *, lomac_object_t * );
+int monitor_read_net_socket( lomac_subject_t *p_subject );
+
+
+#if 0
+void monitor_open( lomac_subject_t *p_subject, lomac_object_t *p_object );
+void monitor_pipe_create( lomac_subject_t *p_subject,
+ lomac_object_t *p_pipe );
+void monitor_unix_socket_bind( lomac_subject_t *p_subject,
+ lomac_object_t *p_socket,
+ lomac_object_t *p_name );
+void monitor_unix_socket_abstract( lomac_subject_t *p_subject,
+ lomac_object_t *p_socket );
+void monitor_unix_socketpair( lomac_subject_t *p_subject,
+ lomac_object_t *p_socket1,
+ lomac_object_t *p_socket2 );
+void monitor_unix_socket_accept_connect( lomac_subject_t *p_subject,
+ lomac_object_t *p_old_socket,
+ lomac_object_t *p_new_socket );
+#endif
+#endif
diff --git a/sys/security/lomac/kernel_pipe.c b/sys/security/lomac/kernel_pipe.c
new file mode 100644
index 0000000..4df9f08
--- /dev/null
+++ b/sys/security/lomac/kernel_pipe.c
@@ -0,0 +1,241 @@
+/*-
+ * Copyright (c) 2001 Networks Associates Technologies, Inc.
+ * All rights reserved.
+ *
+ * This software was developed for the FreeBSD Project 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.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * 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.
+ *
+ * $Id$
+ * $FreeBSD$
+ */
+
+/*
+ * This file contains part of LOMAC's interface to the kernel. This
+ * part allows LOMAC to monitor (unnamed) pipe read and write
+ * operations by interposing control on the kernel's pipeops vector.
+ *
+ * The pipeops vector is defined in kern/sys_pipe.c.
+ *
+ * USAGE:
+ *
+ * The LOMAC LKM should call lomac_initialize_pipes() at LKM load time.
+ * This function turns unnamed pipe interposition on by modifying
+ * the function addresses in pipeops.
+ *
+ * Once the LOMAC LKM turns interposition on, all reads and writes
+ * will pass through this file's monitoring functions.
+ *
+ * This file provides a lomac_uninitialize_pipes() function which
+ * turns unnamed pipe interposition off by restoring pipeops to
+ * its original unmodified state. Once the LOMAC LKM turns
+ * interposition off, subsequent unnamed pipe reads and writes
+ * will not pass through this file's monitoring functions.
+ *
+ * HOW LOMAC HANDLES PIPES:
+ *
+ * (This text describes how LOMAC handles (unnamed) pipes in terms of
+ * abstract architecture-independent concepts.) LOMAC does not treat
+ * pipes as objects, as it does files. When the kernel creates a new
+ * pipe, LOMAC assigns it the highest level. Whenever a process
+ * writes to the pipe, LOMAC reduces the pipe's level to match the
+ * level of the writing process. Whenever a process reads from a
+ * pipe, LOMAC reduces the level of the reading process to match the
+ * pipe's level. As a result, if a high-level process reads the
+ * output of a low-level process through a pipe, the reading process
+ * will wind up at the low level.
+ *
+ * It takes two `struct pipe's to make a pipe. We set the level
+ * information in both `struct pipes', and keep them synchronized.
+ *
+ * This code presently relies on the one-big-kernel-lock to
+ * synchronize its access to the `pipe_state' field of each `struct
+ * pipe'.
+ *
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/file.h>
+#include <sys/selinfo.h>
+#include <sys/pipe.h>
+#include <sys/proc.h>
+#include <sys/uio.h>
+
+#include "lomac.h"
+#include "kernel_interface.h"
+#include "kernel_monitor.h"
+#include "kernel_pipe.h"
+
+
+/* `pipeops' is the kernel's pipe operations vector for the file *
+ * structure. All reads and writes to pipes call through this vector. */
+extern struct fileops pipeops; /* defined in kern/sys_pipe.c */
+
+
+/* These vars store the original addresses of the pipeops read and *
+ * write operations, so we can call them, and even restore them *
+ * later if we want to. */
+static int (*pipe_read_orig)(struct file *, struct uio *, struct ucred *,
+ int, struct thread *);
+static int (*pipe_write_orig)(struct file *, struct uio *, struct ucred *,
+ int, struct thread *);
+
+
+/* declarations of functions private to this module: */
+static int lomac_pipe_read(struct file *, struct uio *, struct ucred *,
+ int, struct thread *);
+static int lomac_pipe_write(struct file *, struct uio *, struct ucred *,
+ int, struct thread *);
+
+/* -------------------- public functions ---------------------------- */
+
+/* lomac_initialize_pipes()
+ *
+ * in: nothing
+ * out: nothing
+ * return: 0
+ *
+ * Turns pipe interposition on by replacing the pipe_read() and pipe_write()
+ * operations in the kernel's pipeops vector with lomac_pipe_read() and
+ * lomac_pipe_write(). Saves the addresses of the original operations
+ * so other functions can call them, and so pipe_interposition_off()
+ * can restore the pipeops vector to its original unmodified state.
+ *
+ */
+
+int
+lomac_initialize_pipes(void) {
+
+ pipe_read_orig = pipeops.fo_read;
+ pipeops.fo_read = lomac_pipe_read;
+ pipe_write_orig = pipeops.fo_write;
+ pipeops.fo_write = lomac_pipe_write;
+ return (0);
+} /* lomac_initialize_pipes() */
+
+
+/* lomac_uninitialize_pipes()
+ *
+ * in: nothing
+ * out: nothing
+ * return: 0
+ *
+ * Turns pipe interposition off by restoring the pipeops vector to its
+ * original unmodified state.
+ *
+ * See note at top of file regarding this function and unloading the
+ * LOMAC LKM.
+ *
+ */
+
+int
+lomac_uninitialize_pipes(void) {
+
+ KASSERT(pipe_read_orig, ("LOMAC:pipe interpositon off before on"));
+ KASSERT(pipe_write_orig, ("LOMAC:pipe interpositon off before on"));
+ pipeops.fo_read = pipe_read_orig;
+ pipeops.fo_write = pipe_write_orig;
+ return (0);
+} /* lomac_uninitialize_pipes() */
+
+
+
+/* ------------------- private functions --------------------------- */
+
+#ifndef MIN
+#define MIN(lo, mac) ((lo) < (mac) ? (lo) : (mac))
+#endif
+
+/* lomac_pipe_read()
+ *
+ * Passes the read operation down to pipe_read_orig(). If
+ * pipe_read_orig() returns success, examines the level of the pipe
+ * and the reading process. If the reading process has a higher
+ * level, reduces the level of the process to equal the pipe's level.
+ *
+ */
+
+static int
+lomac_pipe_read(struct file *fp, struct uio *uio, struct ucred *cred,
+ int flags, struct thread *td) {
+ lomac_object_t read_pipe; /* attrs are in read end of pipe */
+ struct uio kuio;
+ struct iovec kiov;
+ void *buf;
+ int len;
+ int ret_val; /* holds return values */
+
+ len = MIN(uio->uio_resid, BIG_PIPE_SIZE);
+ kiov.iov_base = buf = malloc(len, M_TEMP, M_WAITOK);
+ kiov.iov_len = len;
+ kuio.uio_iov = &kiov;
+ kuio.uio_iovcnt = 1;
+ kuio.uio_offset = 0;
+ kuio.uio_resid = len;
+ kuio.uio_segflg = UIO_SYSSPACE;
+ kuio.uio_rw = UIO_READ;
+ kuio.uio_td = td;
+ ret_val = pipe_read_orig(fp, &kuio, cred, flags, td);
+ if (ret_val == 0) {
+ read_pipe.lo_type = LO_TYPE_PIPE;
+ read_pipe.lo_object.pipe = (struct pipe *)fp->f_data;
+ (void)monitor_read_object(td->td_proc, &read_pipe);
+ ret_val = uiomove(buf, len - kuio.uio_resid, uio);
+ }
+ free(buf, M_TEMP);
+ return (ret_val);
+} /* lomac_pipe_read() */
+
+
+/* lomac_pipe_write()
+ *
+ * Passes the write operation down to pipe_write_orig(). If
+ * pipe_write_orig() returns success, examines the level of the pipe
+ * and the writing process. If the pipe has a higher level than the
+ * writing process, this function reduces the pipe's level to equal
+ * the level of the writing process.
+ *
+ */
+
+static int
+lomac_pipe_write(struct file *fp, struct uio *uio, struct ucred *cred,
+ int flags, struct thread *td) {
+ lomac_object_t pipe;
+ int ret_val; /* holds return values */
+
+ pipe.lo_type = LO_TYPE_PIPE;
+ pipe.lo_object.pipe = (struct pipe *)fp->f_data;
+ ret_val = monitor_pipe_write(td->td_proc, &pipe);
+ if (ret_val == 0)
+ ret_val = pipe_write_orig(fp, uio, cred, flags, td);
+
+ return (ret_val);
+} /* lomac_pipe_write() */
diff --git a/sys/security/lomac/kernel_pipe.h b/sys/security/lomac/kernel_pipe.h
new file mode 100644
index 0000000..de1d01c
--- /dev/null
+++ b/sys/security/lomac/kernel_pipe.h
@@ -0,0 +1,44 @@
+/*-
+ * Copyright (c) 2001 Networks Associates Technologies, Inc.
+ * All rights reserved.
+ *
+ * This software was developed for the FreeBSD Project 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.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * 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.
+ *
+ * $Id$
+ * $FreeBSD$
+ */
+
+#ifndef _KERNEL_PIPE_H_
+#define _KERNEL_PIPE_H_
+
+int lomac_initialize_pipes( void );
+int lomac_uninitialize_pipes( void );
+
+#endif /* _KERNEL_PIPE_H_ */
diff --git a/sys/security/lomac/kernel_plm.c b/sys/security/lomac/kernel_plm.c
new file mode 100644
index 0000000..1386704
--- /dev/null
+++ b/sys/security/lomac/kernel_plm.c
@@ -0,0 +1,382 @@
+/*-
+ * Copyright (c) 2001 Networks Associates Technologies, Inc.
+ * All rights reserved.
+ *
+ * This software was developed for the FreeBSD Project 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.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * 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.
+ *
+ * $Id$
+ * $FreeBSD$
+ */
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/queue.h>
+#include <sys/systm.h>
+#include <sys/vnode.h>
+#include <sys/namei.h>
+
+#include "kernel_interface.h"
+#include "kernel_plm.h"
+#include "lomacfs.h"
+#include "policy_plm.h"
+
+MALLOC_DEFINE(M_LOMACPLM, "LOMAC_PLM", "LOMAC PLM nodes and strings");
+char *strsep(register char **stringp, register const char *delim);
+
+/*
+ * Get next token from string *stringp, where tokens are possibly-empty
+ * strings separated by characters from delim.
+ *
+ * Writes NULs into the string at *stringp to end tokens.
+ * delim need not remain constant from call to call.
+ * On return, *stringp points past the last NUL written (if there might
+ * be further tokens), or is NULL (if there are definitely no more tokens).
+ *
+ * If *stringp is NULL, strsep returns NULL.
+ */
+char *
+strsep(stringp, delim)
+ register char **stringp;
+ register const char *delim;
+{
+ register char *s;
+ register const char *spanp;
+ register int c, sc;
+ char *tok;
+
+ if ((s = *stringp) == NULL)
+ return (NULL);
+ for (tok = s;;) {
+ c = *s++;
+ spanp = delim;
+ do {
+ if ((sc = *spanp++) == c) {
+ if (c == 0)
+ s = NULL;
+ else
+ s[-1] = 0;
+ *stringp = s;
+ return (tok);
+ }
+ } while (sc != 0);
+ }
+ /* NOTREACHED */
+}
+
+struct lomac_node_entry lomac_node_entry_root = {
+ SLIST_HEAD_INITIALIZER(lomac_node_entry),
+ { NULL },
+ LN_HIGHEST_LEVEL | LN_INHERIT_HIGH,
+ "/"
+};
+
+static struct lomac_node_entry *
+lomac_plm_subtree_find_cnp(struct lomac_node_entry *root,
+ struct componentname *cnp) {
+ char *nameptr = cnp->cn_nameptr;
+ struct lomac_node_entry *lne;
+ int len = cnp->cn_namelen;
+
+ SLIST_FOREACH(lne, &root->ln_children, ln_chain)
+ if (strlen(lne->ln_name) == len &&
+ bcmp(lne->ln_name, nameptr, len) == 0)
+ break;
+
+ return (lne);
+}
+
+static struct lomac_node_entry *
+lomac_plm_subtree_find(struct lomac_node_entry *root, const char *name) {
+ struct lomac_node_entry *lne;
+
+ SLIST_FOREACH(lne, &root->ln_children, ln_chain)
+ if (strcmp(name, lne->ln_name) == 0)
+ break;
+
+ return (lne);
+}
+
+
+/*
+ * This is called from inside getnewvnode() before the vnode is in use.
+ */
+void
+lomac_plm_init_lomacfs_vnode(struct vnode *dvp, struct vnode *vp,
+ struct componentname *cnp, lattr_t *subjlattr) {
+ struct lomac_node *ln = VTOLOMAC(vp);
+ struct lomac_node_entry *mlne = NULL;
+
+ /*
+ * Only "/" has no parent, so inherit directly from our PLM root.
+ */
+ if (dvp == NULL) {
+ ln->ln_flags = lomac_node_entry_root.ln_flags;
+ ln->ln_entry = ln->ln_underpolicy = &lomac_node_entry_root;
+ } else {
+ struct lomac_node *dln = VTOLOMAC(dvp);
+ struct lomac_node_entry *dlne = dln->ln_entry;
+ int fixup_inherit = 0;
+
+ /*
+ * If we have no directory-specific entry, we inherit
+ * directly from the lomac_node's previously-inherited
+ * flags implicitly, otherwise we inherit explicitly
+ * from the corresponding lomac_node_entry.
+ */
+ if (dlne == NULL) {
+ ln->ln_flags = dln->ln_flags & LN_INHERIT_MASK;
+ fixup_inherit = 1;
+ ln->ln_underpolicy = dln->ln_underpolicy;
+ ln->ln_entry = NULL;
+ } else if ((mlne = lomac_plm_subtree_find_cnp(dlne, cnp)) ==
+ NULL) {
+ ln->ln_flags = dlne->ln_flags & LN_INHERIT_MASK;
+ fixup_inherit = 2;
+ ln->ln_underpolicy = dlne;
+ ln->ln_entry = NULL;
+ } else {
+ ln->ln_entry = ln->ln_underpolicy = mlne;
+ }
+ if (fixup_inherit) {
+ switch (ln->ln_flags) {
+ case LN_INHERIT_LOW:
+ ln->ln_flags |= LN_LOWEST_LEVEL;
+ break;
+ case LN_INHERIT_SUBJ:
+ if (subjlattr->level == LOMAC_HIGHEST_LEVEL)
+ ln->ln_flags |= LN_HIGHEST_LEVEL;
+ else {
+ ln->ln_flags &= ~LN_INHERIT_MASK;
+ ln->ln_flags |= LN_INHERIT_LOW |
+ LN_LOWEST_LEVEL;
+ }
+ break;
+ case LN_INHERIT_HIGH:
+ ln->ln_flags |= LN_HIGHEST_LEVEL;
+ break;
+ }
+ if (fixup_inherit == 2)
+ ln->ln_flags |=
+ (dlne->ln_flags & LN_CHILD_ATTR_MASK) >>
+ LN_CHILD_ATTR_SHIFT;
+ } else {
+ /* this is the only case where mlne != NULL */
+ ln->ln_flags &= ~(LN_INHERIT_MASK | LN_ATTR_MASK);
+ ln->ln_flags |= mlne->ln_flags &
+ (LN_INHERIT_MASK | LN_ATTR_MASK);
+ if ((mlne->ln_flags & LN_LEVEL_MASK) ==
+ LN_SUBJ_LEVEL) {
+ if (subjlattr->level == LOMAC_HIGHEST_LEVEL)
+ ln->ln_flags |= LN_HIGHEST_LEVEL;
+ else
+ ln->ln_flags |= LN_LOWEST_LEVEL;
+ } else
+ ln->ln_flags |= mlne->ln_flags & LN_LEVEL_MASK;
+ }
+ }
+
+ KASSERT(ln->ln_flags & LN_LEVEL_MASK, ("lomac_node has no level"));
+ KASSERT(ln->ln_flags & LN_INHERIT_MASK, ("lomac_node has no inherit"));
+#ifdef INVARIANTS
+ if (mlne != NULL) {
+ KASSERT(mlne->ln_flags & LN_LEVEL_MASK,
+ ("lomac_node_entry has no level"));
+ KASSERT(mlne->ln_flags & LN_INHERIT_MASK,
+ ("lomac_node_entry has no inherit"));
+ }
+#endif /* INVARIANTS */
+}
+
+static struct lomac_node_entry *
+lomac_plm_subtree_new(struct lomac_node_entry *plne, char *name) {
+ struct lomac_node_entry *lne;
+ static struct lomac_node_entry_head head_init =
+ SLIST_HEAD_INITIALIZER(lomac_node_entry);
+
+ lne = malloc(sizeof(*lne), M_LOMACPLM, M_WAITOK);
+ bcopy(&head_init, &lne->ln_children, sizeof(head_init));
+ lne->ln_name = name;
+ lne->ln_flags = plne->ln_flags & LN_INHERIT_MASK;
+ switch (lne->ln_flags) {
+ case LN_INHERIT_LOW:
+ lne->ln_flags |= LN_LOWEST_LEVEL;
+ break;
+ case LN_INHERIT_HIGH:
+ lne->ln_flags |= LN_HIGHEST_LEVEL;
+ break;
+ case LN_INHERIT_SUBJ:
+ lne->ln_flags |= LN_SUBJ_LEVEL;
+ break;
+ }
+ SLIST_INSERT_HEAD(&plne->ln_children, lne, ln_chain);
+ return (lne);
+}
+
+static void
+lomac_plm_subtree_free(struct lomac_node_entry *lneself) {
+ struct lomac_node_entry_head *head = &lneself->ln_children;
+ struct lomac_node_entry *lne;
+
+ while (!SLIST_EMPTY(head)) {
+ lne = SLIST_FIRST(head);
+ SLIST_REMOVE_HEAD(head, ln_chain);
+ lomac_plm_subtree_free(lne);
+ }
+ free(lneself, M_LOMACPLM);
+}
+
+struct string_list {
+ SLIST_ENTRY(string_list) entries;
+ char string[1];
+};
+static SLIST_HEAD(, string_list) string_list_head =
+ SLIST_HEAD_INITIALIZER(string_list);
+
+static char *
+string_list_new(const char *s) {
+ struct string_list *sl;
+
+ sl = malloc(sizeof(*sl) + strlen(s), M_LOMACPLM, M_WAITOK);
+ strcpy(sl->string, s);
+ SLIST_INSERT_HEAD(&string_list_head, sl, entries);
+
+ return (sl->string);
+}
+
+static void
+lomac_plm_uninitialize(void) {
+ struct lomac_node_entry_head *head = &lomac_node_entry_root.ln_children;
+ struct lomac_node_entry *lne;
+ struct string_list *sl;
+
+ while (!SLIST_EMPTY(head)) {
+ lne = SLIST_FIRST(head);
+ SLIST_REMOVE_HEAD(head, ln_chain);
+ lomac_plm_subtree_free(lne);
+ }
+ while (!SLIST_EMPTY(&string_list_head)) {
+ sl = SLIST_FIRST(&string_list_head);
+ SLIST_REMOVE_HEAD(&string_list_head, entries);
+ free(sl, M_LOMACPLM);
+ }
+}
+
+static int
+lomac_plm_initialize(void) {
+ struct lomac_node_entry *plne, *lne;
+ plm_rule_t *pr;
+
+ for (pr = plm; pr->path != NULL; pr++) {
+ char *path;
+ char *comp;
+ int depth;
+
+ if (*pr->path == '\0') {
+ printf("lomac_plm: invalid path \"%s\"\n", pr->path);
+ return (EINVAL);
+ }
+ path = string_list_new(pr->path);
+ lne = &lomac_node_entry_root;
+ depth = 0;
+ for (;; depth++) {
+ plne = lne;
+ comp = strsep(&path, "/");
+ if (comp == NULL)
+ break;
+ if (depth == 0) { /* special case: beginning / */
+ if (*comp == '\0')
+ continue;
+ else {
+ printf("lomac_plm: not absolute path "
+ "\"%s\"\n", pr->path);
+ return (EINVAL);
+ }
+ } else if (depth == 1) { /* special case: "/" */
+ if (*comp == '\0' && strsep(&path, "/") == NULL)
+ break;
+ }
+ if (*comp == '\0' ||
+ strcmp(comp, ".") == 0 ||
+ strcmp(comp, "..") == 0) {
+ printf("lomac_plm: empty path component in "
+ "\"%s\"\n", pr->path);
+ return (EINVAL);
+ }
+ lne = lomac_plm_subtree_find(plne, comp);
+ if (lne == NULL) {
+ lne = lomac_plm_subtree_new(plne, comp);
+ lne->ln_path = plne->ln_path;
+ }
+ }
+ lne->ln_path = pr->path;
+ if (pr->flags == PLM_NOFLAGS)
+ lne->ln_flags &= ~LN_LEVEL_MASK;
+ else
+ lne->ln_flags &= ~LN_INHERIT_MASK;
+ lne->ln_flags |=
+ plm_levelflags_to_node_flags[pr->level][pr->flags];
+ if (pr->flags == PLM_NOFLAGS)
+ lne->ln_flags |= pr->attr;
+ else
+ lne->ln_flags |= (pr->attr & LN_ATTR_MASK)
+ << LN_CHILD_ATTR_SHIFT;
+ }
+ return (0);
+}
+
+int lomac_plm_initialized = 0;
+
+static int
+lomac_plm_modevent(module_t module, int event, void *unused) {
+ int error = 0;
+
+ switch ((enum modeventtype)event) {
+ case MOD_LOAD:
+ error = lomac_plm_initialize();
+ if (error == 0)
+ lomac_plm_initialized = 1;
+ break;
+ case MOD_UNLOAD:
+ lomac_plm_uninitialize();
+ case MOD_SHUTDOWN:
+ break;
+ }
+ return (error);
+}
+
+static moduledata_t lomac_plm_moduledata = {
+ "lomac_plm",
+ &lomac_plm_modevent,
+ NULL
+};
+DECLARE_MODULE(lomac_plm, lomac_plm_moduledata, SI_SUB_VFS, SI_ORDER_ANY);
+MODULE_VERSION(lomac_plm, 1);
diff --git a/sys/security/lomac/kernel_plm.h b/sys/security/lomac/kernel_plm.h
new file mode 100644
index 0000000..8676d06
--- /dev/null
+++ b/sys/security/lomac/kernel_plm.h
@@ -0,0 +1,45 @@
+/*-
+ * Copyright (c) 2001 Networks Associates Technologies, Inc.
+ * All rights reserved.
+ *
+ * This software was developed for the FreeBSD Project 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.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * 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.
+ *
+ * $Id$
+ * $FreeBSD$
+ */
+
+#ifndef KERNEL_PLM_H
+#define KERNEL_PLM_H
+
+extern int lomac_plm_initialized; /* set to 1 if successfully initialized */
+void lomac_plm_init_lomacfs_vnode(struct vnode *dvp, struct vnode *vp,
+ struct componentname *cnp, lattr_t *subjlattr);
+
+#endif /* KERNEL_PLM_H */
diff --git a/sys/security/lomac/kernel_socket.c b/sys/security/lomac/kernel_socket.c
new file mode 100644
index 0000000..7cf6669
--- /dev/null
+++ b/sys/security/lomac/kernel_socket.c
@@ -0,0 +1,784 @@
+/*-
+ * Copyright (c) 2001 Networks Associates Technologies, Inc.
+ * Copyright (c) 1982, 1986, 1989, 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed for the FreeBSD Project 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.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * 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.
+ *
+ * $Id$
+ * $FreeBSD$
+ */
+
+/*
+ * This file implements LOMAC controls over socket operations. LOMAC
+ * gains control of socket operations by interposing on the `struct
+ * pr_usrreqs' operations vectors of each `struct protosw'. This code
+ * replaces each `struct pr_usrreqs' with an instance of `struct
+ * lomac_pr_usrreqs' containing LOMAC socket control functions. These
+ * socket control functions implement LOMAC's socket controls, and then
+ * call the corresponding socket operations from the original `struct
+ * pr_usrreqs'. Each instance of `struct lomac_pr_usrreqs' ends with
+ * a pointer to the `struct pr_usrreqs' it replaces. These pointers
+ * allow the LOMAC socket control functions to find their corresponding
+ * original `struct pr_usrreqs' functions.
+ *
+ * This file provides the function lomac_initialize_sockets() to turn
+ * socket interposition on. Once socket iterposition is turned on,
+ * the kernel will begin to call LOMAC's socket control functions.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/kernel.h>
+#include <sys/proc.h>
+#include <sys/resourcevar.h>
+
+#include <sys/domain.h>
+#include <sys/mbuf.h>
+#include <sys/namei.h>
+#include <sys/protosw.h>
+#include <sys/socketvar.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/unpcb.h>
+#include <sys/uio.h>
+#include <sys/vnode.h>
+
+#include "kernel_interface.h"
+#include "kernel_socket.h"
+#include "kernel_mediate.h"
+#include "kernel_monitor.h"
+#include "lomacfs.h"
+
+MALLOC_DEFINE(M_LOMAC_USRREQS, "LOMAC-UR", "LOMAC usrreqs");
+
+struct lomac_pr_usrreqs {
+ struct pr_usrreqs lomac_pr_usrreqs; /* LOMAC socket control fxns */
+ struct pr_usrreqs *orig_pr_usrreqs; /* original socket op vector */
+};
+
+int lomac_local_accept(struct socket *, struct sockaddr **);
+int lomac_local_connect(struct socket *, struct sockaddr *, struct thread *);
+int lomac_local_connect2(struct socket *, struct socket *);
+int lomac_local_detach(struct socket *);
+int lomac_local_send( struct socket *, int, struct mbuf *, struct sockaddr *,
+ struct mbuf *, struct thread * );
+int lomac_soreceive( struct socket *, struct sockaddr **, struct uio *,
+ struct mbuf **, struct mbuf **, int * );
+int lomac_local_soreceive( struct socket *, struct sockaddr **, struct uio *,
+ struct mbuf **, struct mbuf **, int * );
+static int monitored_soreceive( struct socket *, struct sockaddr **,
+ struct uio *, struct mbuf **, struct mbuf **, int * );
+
+/* This usrreqs structure implements LOMAC's controls on local sockets */
+struct pr_usrreqs lomac_local_usrreqs = {
+ NULL,
+ lomac_local_accept,
+ NULL,
+ NULL,
+ lomac_local_connect,
+ lomac_local_connect2,
+ NULL,
+ lomac_local_detach,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ lomac_local_send,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ lomac_local_soreceive,
+ NULL
+};
+
+/* This usrreqs structure implements LOMAC's controls on network sockets */
+struct pr_usrreqs lomac_net_usrreqs = {
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ lomac_soreceive,
+ NULL
+};
+
+static __inline struct pr_usrreqs *
+orig_pr_usrreqs( struct socket *so ) {
+ return (((struct lomac_pr_usrreqs *)(so->so_proto->pr_usrreqs))->
+ orig_pr_usrreqs);
+}
+
+int
+lomac_local_accept( struct socket *so, struct sockaddr **nam ) {
+ struct vnode *vp;
+ struct unpcb *unp;
+ int ret_val; /* value to return to caller */
+
+ unp = sotounpcb(so);
+ if (unp == NULL)
+ return (EINVAL);
+ if (unp->unp_conn != NULL) {
+ vp = unp->unp_vnode = unp->unp_conn->unp_vnode;
+ if (vp != NULL)
+ vref(vp);
+ }
+ ret_val = (*orig_pr_usrreqs(so)->pru_accept)(so, nam);
+ return (ret_val);
+}
+
+int
+lomac_local_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
+{
+ register struct sockaddr_un *soun = (struct sockaddr_un *)nam;
+ register struct vnode *vp;
+ register struct socket *so2, *so3;
+ struct unpcb *unp, *unp2, *unp3;
+ int error, len;
+ struct nameidata nd;
+ char buf[SOCK_MAXADDRLEN];
+
+ len = nam->sa_len - offsetof(struct sockaddr_un, sun_path);
+ if (len <= 0)
+ return EINVAL;
+ strncpy(buf, soun->sun_path, len);
+ buf[len] = 0;
+
+ NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, buf, td);
+ error = namei(&nd);
+ if (error)
+ goto bad2;
+ vp = nd.ni_vp;
+ NDFREE(&nd, NDF_ONLY_PNBUF);
+ if (vp->v_type != VSOCK) {
+ error = ENOTSOCK;
+ goto bad;
+ }
+ error = VOP_ACCESS(vp, VWRITE, td->td_proc->p_ucred, td);
+ if (error)
+ goto bad;
+ so2 = vp->v_socket;
+ if (so2 == 0) {
+ error = ECONNREFUSED;
+ goto bad;
+ }
+ if (so->so_type != so2->so_type) {
+ error = EPROTOTYPE;
+ goto bad;
+ }
+ if (so->so_proto->pr_flags & PR_CONNREQUIRED) {
+ if ((so2->so_options & SO_ACCEPTCONN) == 0 ||
+ (so3 = sonewconn3(so2, 0, td)) == 0) {
+ error = ECONNREFUSED;
+ goto bad;
+ }
+ unp = sotounpcb(so);
+ unp2 = sotounpcb(so2);
+ unp3 = sotounpcb(so3);
+ if (unp2->unp_addr)
+ unp3->unp_addr = (struct sockaddr_un *)
+ dup_sockaddr((struct sockaddr *)
+ unp2->unp_addr, 1);
+
+ /*
+ * unp_peercred management:
+ *
+ * The connecter's (client's) credentials are copied
+ * from its process structure at the time of connect()
+ * (which is now).
+ */
+ memset(&unp3->unp_peercred, '\0', sizeof(unp3->unp_peercred));
+ unp3->unp_peercred.cr_uid = td->td_proc->p_ucred->cr_uid;
+ unp3->unp_peercred.cr_ngroups = td->td_proc->p_ucred->cr_ngroups;
+ memcpy(unp3->unp_peercred.cr_groups, td->td_proc->p_ucred->cr_groups,
+ sizeof(unp3->unp_peercred.cr_groups));
+ unp3->unp_flags |= UNP_HAVEPC;
+ /*
+ * The receiver's (server's) credentials are copied
+ * from the unp_peercred member of socket on which the
+ * former called listen(); unp_listen() cached that
+ * process's credentials at that time so we can use
+ * them now.
+ */
+ KASSERT(unp2->unp_flags & UNP_HAVEPCCACHED,
+ ("unp_connect: listener without cached peercred"));
+ memcpy(&unp->unp_peercred, &unp2->unp_peercred,
+ sizeof(unp->unp_peercred));
+ unp->unp_flags |= UNP_HAVEPC;
+
+ so2 = so3;
+ }
+ error = lomac_local_connect2(so, so2);
+bad:
+ vput(vp);
+bad2:
+ return (error);
+}
+
+int
+lomac_local_connect2( struct socket *so1, struct socket *so2 ) {
+ struct vnode *vp;
+ int ret_val; /* value to return to caller */
+
+ if (so2->so_head != NULL) {
+ vp = sotounpcb(so2->so_head)->unp_vnode;
+ if (vp != NULL) {
+ sotounpcb(so1)->unp_vnode = vp;
+ vref(vp);
+ }
+ }
+ ret_val = (*orig_pr_usrreqs(so1)->pru_connect2)(so1, so2);
+ return (ret_val);
+}
+
+int
+lomac_local_detach( struct socket *so ) {
+ int ret_val; /* value to return to caller */
+ struct unpcb *unp = sotounpcb(so);
+
+ if (unp == NULL)
+ return (EINVAL);
+ if (unp->unp_vnode != NULL && unp->unp_vnode->v_socket != so) {
+ vrele(unp->unp_vnode);
+ unp->unp_vnode = NULL;
+ }
+ ret_val = (*orig_pr_usrreqs(so)->pru_detach)(so);
+ return (ret_val);
+}
+
+int
+lomac_local_send( struct socket *so, int flags, struct mbuf *m,
+ struct sockaddr *addr, struct mbuf *control, struct thread *td ) {
+ struct vnode *vp;
+ struct unpcb *unp = sotounpcb(so);
+ int error;
+
+ /* printf( "pid %d local send\n", p->p_pid ); */
+ if (unp == NULL) {
+ error = EINVAL;
+ goto out;
+ }
+ if (so->so_type == SOCK_DGRAM) {
+ if (addr != NULL) {
+ if (unp->unp_conn != NULL) {
+ error = EISCONN;
+ goto out;
+ }
+ error = lomac_local_connect(so, addr, td);
+ if (error)
+ goto out;
+ } else if (unp->unp_conn == NULL) {
+ error = ENOTCONN;
+ goto out;
+ }
+ } else if ((so->so_state & SS_ISCONNECTED) == 0) {
+ if (addr != NULL) {
+ error = lomac_local_connect(so, addr, td);
+ if (error)
+ goto out; /* XXX */
+ } else {
+ error = ENOTCONN;
+ goto out;
+ }
+ }
+ vp = unp->unp_vnode;
+ if (vp != NULL) {
+ lomac_object_t lobj;
+
+ lobj.lo_type = VISLOMAC(vp) ? LO_TYPE_LVNODE : LO_TYPE_UVNODE;
+ lobj.lo_object.vnode = vp;
+ if (!mediate_subject_object("send", td->td_proc, &lobj)) {
+ error = EPERM;
+ goto out;
+ }
+ } else {
+ /*
+ * This is a send to a socket in a socketpair() pair.
+ * Mark both sockets in pair with the appropriate level.
+ */
+ lomac_object_t lobj1, lobj2;
+ lattr_t lattr;
+
+ lobj1.lo_type = LO_TYPE_SOCKETPAIR;
+ lobj1.lo_object.socket = so;
+ if ((error = monitor_pipe_write(td->td_proc, &lobj1)) != 0)
+ goto out;
+ lobj2.lo_type = LO_TYPE_SOCKETPAIR;
+ lobj2.lo_object.socket = unp->unp_conn->unp_socket;
+ get_object_lattr(&lobj1, &lattr);
+ set_object_lattr(&lobj2, lattr);
+ }
+ error = (*orig_pr_usrreqs(so)->pru_send)( so, flags, m, NULL,
+ control, td );
+ if (addr != NULL && so->so_type == SOCK_DGRAM)
+ (*orig_pr_usrreqs(so)->pru_disconnect)(so);
+out:
+ return (error);
+}
+
+
+
+int
+lomac_local_soreceive(struct socket *so, struct sockaddr **paddr,
+ struct uio *uio, struct mbuf **mp0, struct mbuf **controlp, int *flagsp) {
+ lomac_object_t lobj;
+ struct vnode *vp;
+ struct unpcb *unp = sotounpcb(so);
+ int ret_val; /* value to return to caller */
+
+ if (unp == NULL)
+ return (EINVAL);
+ vp = unp->unp_vnode;
+ if (vp != NULL) {
+ lobj.lo_type = VISLOMAC(vp) ? LO_TYPE_LVNODE : LO_TYPE_UVNODE;
+ lobj.lo_object.vnode = vp;
+ ret_val = monitor_read_object(uio->uio_td->td_proc, &lobj);
+ if (ret_val == 0)
+ ret_val = (*orig_pr_usrreqs(so)->pru_soreceive)(so,
+ paddr, uio, mp0, controlp, flagsp);
+ } else {
+ /*
+ * This is a receive from a socket in a pair created by
+ * socketpair(). Monitor it as we would a pipe read,
+ * except for allowing for arbitrary numbers of sleeps.
+ */
+ ret_val = monitored_soreceive(so, paddr, uio, mp0, controlp,
+ flagsp);
+ }
+ return (ret_val);
+}
+
+int
+lomac_soreceive(struct socket *so, struct sockaddr **paddr, struct uio *uio,
+ struct mbuf **mp0, struct mbuf **controlp, int *flagsp) {
+ int ret_val; /* value to return to caller */
+
+ (void)monitor_read_net_socket(uio->uio_td->td_proc);
+ ret_val = (*orig_pr_usrreqs(so)->pru_soreceive)(so, paddr, uio, mp0,
+ controlp, flagsp);
+ return (ret_val);
+}
+
+int
+lomac_initialize_sockets(void) {
+ struct domain *dp; /* used to traverse global `domains' list */
+ struct protosw *pr; /* used to traverse each domain's protosw list */
+ struct lomac_pr_usrreqs *lomac_pr_usrreqs; /* lomac usrreqs vectors */
+ void (**lfuncp)(void), (**funcp)(void);
+ int n, nreq;
+
+ nreq = sizeof(struct pr_usrreqs) / sizeof(void (*)(void));
+ for (dp = domains; dp; dp = dp->dom_next) {
+ for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++) {
+
+ lomac_pr_usrreqs = (struct lomac_pr_usrreqs *)malloc(
+ sizeof(struct lomac_pr_usrreqs), M_LOMAC_USRREQS,
+ M_WAITOK);
+
+ if (dp->dom_family == AF_LOCAL)
+ memcpy(lomac_pr_usrreqs, &lomac_local_usrreqs,
+ sizeof(struct pr_usrreqs));
+ else
+ memcpy(lomac_pr_usrreqs, &lomac_net_usrreqs,
+ sizeof(struct pr_usrreqs));
+ /*
+ * Do sparse allocation of user requests and only
+ * override the ones we need to (to reduce overhead).
+ */
+ lfuncp = (void (**)(void))lomac_pr_usrreqs;
+ funcp = (void (**)(void))pr->pr_usrreqs;
+ for (n = 0; n < nreq; n++) {
+ if (lfuncp[n] == NULL)
+ lfuncp[n] = funcp[n];
+ }
+ lomac_pr_usrreqs->orig_pr_usrreqs = pr->pr_usrreqs;
+ pr->pr_usrreqs = (struct pr_usrreqs *)lomac_pr_usrreqs;
+ }
+ }
+ return (0);
+}
+
+
+int
+lomac_uninitialize_sockets(void) {
+ struct domain *dp; /* used to traverse global `domains' list */
+ struct protosw *pr; /* used to traverse each domain's protosw list */
+ struct lomac_pr_usrreqs *lomac_pr_usrreqs; /* lomac usrreqs vectors */
+
+ for (dp = domains; dp; dp = dp->dom_next) {
+ for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++) {
+ lomac_pr_usrreqs = (struct lomac_pr_usrreqs *)
+ pr->pr_usrreqs;
+ pr->pr_usrreqs = lomac_pr_usrreqs->orig_pr_usrreqs;
+ free(lomac_pr_usrreqs, M_LOMAC_USRREQS);
+ }
+ }
+ return (0);
+}
+
+#define SBLOCKWAIT(f) (((f) & MSG_DONTWAIT) ? M_NOWAIT : M_WAITOK)
+/*
+ * Implement receive operations on a socket.
+ * We depend on the way that records are added to the sockbuf
+ * by sbappend*. In particular, each record (mbufs linked through m_next)
+ * must begin with an address if the protocol so specifies,
+ * followed by an optional mbuf or mbufs containing ancillary data,
+ * and then zero or more mbufs of data.
+ * In order to avoid blocking network interrupts for the entire time here,
+ * we splx() while doing the actual copy to user space.
+ * Although the sockbuf is locked, new data may still be appended,
+ * and thus we must maintain consistency of the sockbuf during that time.
+ *
+ * The caller may receive the data as a single mbuf chain by supplying
+ * an mbuf **mp0 for use in returning the chain. The uio is then used
+ * only for the count in uio_resid.
+ */
+static int
+monitored_soreceive(so, psa, uio, mp0, controlp, flagsp)
+ register struct socket *so;
+ struct sockaddr **psa;
+ struct uio *uio;
+ struct mbuf **mp0;
+ struct mbuf **controlp;
+ int *flagsp;
+{
+ lomac_object_t lobj;
+ register struct mbuf *m, **mp;
+ register int flags, len, error, s, offset;
+ struct protosw *pr = so->so_proto;
+ struct mbuf *nextrecord;
+ struct proc *p;
+ int moff, type = 0;
+ int orig_resid = uio->uio_resid;
+
+ mp = mp0;
+ if (psa)
+ *psa = 0;
+ if (controlp)
+ *controlp = 0;
+ if (flagsp)
+ flags = *flagsp &~ MSG_EOR;
+ else
+ flags = 0;
+ lobj.lo_type = LO_TYPE_SOCKETPAIR;
+ lobj.lo_object.socket = so;
+ if (uio->uio_td != NULL) /* XXX */
+ p = uio->uio_td->td_proc;
+ else
+ p = curthread->td_proc;
+ if (flags & MSG_OOB) {
+ m = m_get(M_TRYWAIT, MT_DATA);
+ if (m == NULL)
+ return (ENOBUFS);
+ error = (*pr->pr_usrreqs->pru_rcvoob)(so, m, flags & MSG_PEEK);
+ if (error)
+ goto bad;
+ do {
+ monitor_read_object(p, &lobj);
+ error = uiomove(mtod(m, caddr_t),
+ (int) min(uio->uio_resid, m->m_len), uio);
+ m = m_free(m);
+ } while (uio->uio_resid && error == 0 && m);
+bad:
+ if (m)
+ m_freem(m);
+ return (error);
+ }
+ if (mp)
+ *mp = (struct mbuf *)0;
+ if (so->so_state & SS_ISCONFIRMING && uio->uio_resid)
+ (*pr->pr_usrreqs->pru_rcvd)(so, 0);
+
+restart:
+ error = sblock(&so->so_rcv, SBLOCKWAIT(flags));
+ if (error)
+ return (error);
+ s = splnet();
+
+ m = so->so_rcv.sb_mb;
+ /*
+ * If we have less data than requested, block awaiting more
+ * (subject to any timeout) if:
+ * 1. the current count is less than the low water mark, or
+ * 2. MSG_WAITALL is set, and it is possible to do the entire
+ * receive operation at once if we block (resid <= hiwat).
+ * 3. MSG_DONTWAIT is not set
+ * If MSG_WAITALL is set but resid is larger than the receive buffer,
+ * we have to do the receive in sections, and thus risk returning
+ * a short count if a timeout or signal occurs after we start.
+ */
+ if (m == 0 || (((flags & MSG_DONTWAIT) == 0 &&
+ so->so_rcv.sb_cc < uio->uio_resid) &&
+ (so->so_rcv.sb_cc < so->so_rcv.sb_lowat ||
+ ((flags & MSG_WAITALL) && uio->uio_resid <= so->so_rcv.sb_hiwat)) &&
+ m->m_nextpkt == 0 && (pr->pr_flags & PR_ATOMIC) == 0)) {
+ KASSERT(m != 0 || !so->so_rcv.sb_cc,
+ ("receive: m == %p so->so_rcv.sb_cc == %lu",
+ m, so->so_rcv.sb_cc));
+ if (so->so_error) {
+ if (m)
+ goto dontblock;
+ error = so->so_error;
+ if ((flags & MSG_PEEK) == 0)
+ so->so_error = 0;
+ goto release;
+ }
+ if (so->so_state & SS_CANTRCVMORE) {
+ if (m)
+ goto dontblock;
+ else
+ goto release;
+ }
+ for (; m; m = m->m_next)
+ if (m->m_type == MT_OOBDATA || (m->m_flags & M_EOR)) {
+ m = so->so_rcv.sb_mb;
+ goto dontblock;
+ }
+ if ((so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) == 0 &&
+ (so->so_proto->pr_flags & PR_CONNREQUIRED)) {
+ error = ENOTCONN;
+ goto release;
+ }
+ if (uio->uio_resid == 0)
+ goto release;
+ if ((so->so_state & SS_NBIO) || (flags & MSG_DONTWAIT)) {
+ error = EWOULDBLOCK;
+ goto release;
+ }
+ sbunlock(&so->so_rcv);
+ error = sbwait(&so->so_rcv);
+ splx(s);
+ if (error)
+ return (error);
+ goto restart;
+ }
+dontblock:
+ if (uio->uio_td)
+ p->p_stats->p_ru.ru_msgrcv++;
+ nextrecord = m->m_nextpkt;
+ if (pr->pr_flags & PR_ADDR) {
+ KASSERT(m->m_type == MT_SONAME, ("receive 1a"));
+ orig_resid = 0;
+ if (psa)
+ *psa = dup_sockaddr(mtod(m, struct sockaddr *),
+ mp0 == 0);
+ if (flags & MSG_PEEK) {
+ m = m->m_next;
+ } else {
+ sbfree(&so->so_rcv, m);
+ MFREE(m, so->so_rcv.sb_mb);
+ m = so->so_rcv.sb_mb;
+ }
+ }
+ while (m && m->m_type == MT_CONTROL && error == 0) {
+ if (flags & MSG_PEEK) {
+ if (controlp)
+ *controlp = m_copy(m, 0, m->m_len);
+ m = m->m_next;
+ } else {
+ sbfree(&so->so_rcv, m);
+ so->so_rcv.sb_mb = m->m_next;
+ m->m_next = NULL;
+ if (pr->pr_domain->dom_externalize)
+ error =
+ (*pr->pr_domain->dom_externalize)(m, controlp);
+ else if (controlp)
+ *controlp = m;
+ else
+ m_freem(m);
+ m = so->so_rcv.sb_mb;
+ }
+ if (controlp) {
+ orig_resid = 0;
+ do
+ controlp = &(*controlp)->m_next;
+ while (*controlp != NULL);
+ }
+ }
+ if (m) {
+ if ((flags & MSG_PEEK) == 0)
+ m->m_nextpkt = nextrecord;
+ type = m->m_type;
+ if (type == MT_OOBDATA)
+ flags |= MSG_OOB;
+ }
+ moff = 0;
+ offset = 0;
+ while (m && uio->uio_resid > 0 && error == 0) {
+ if (m->m_type == MT_OOBDATA) {
+ if (type != MT_OOBDATA)
+ break;
+ } else if (type == MT_OOBDATA)
+ break;
+ else
+ KASSERT(m->m_type == MT_DATA || m->m_type == MT_HEADER,
+ ("receive 3"));
+ so->so_state &= ~SS_RCVATMARK;
+ len = uio->uio_resid;
+ if (so->so_oobmark && len > so->so_oobmark - offset)
+ len = so->so_oobmark - offset;
+ if (len > m->m_len - moff)
+ len = m->m_len - moff;
+ /*
+ * If mp is set, just pass back the mbufs.
+ * Otherwise copy them out via the uio, then free.
+ * Sockbuf must be consistent here (points to current mbuf,
+ * it points to next record) when we drop priority;
+ * we must note any additions to the sockbuf when we
+ * block interrupts again.
+ */
+ if (mp == 0) {
+ splx(s);
+ monitor_read_object(p, &lobj);
+ error = uiomove(mtod(m, caddr_t) + moff, (int)len, uio);
+ s = splnet();
+ if (error)
+ goto release;
+ } else
+ uio->uio_resid -= len;
+ if (len == m->m_len - moff) {
+ if (m->m_flags & M_EOR)
+ flags |= MSG_EOR;
+ if (flags & MSG_PEEK) {
+ m = m->m_next;
+ moff = 0;
+ } else {
+ nextrecord = m->m_nextpkt;
+ sbfree(&so->so_rcv, m);
+ if (mp) {
+ *mp = m;
+ mp = &m->m_next;
+ so->so_rcv.sb_mb = m = m->m_next;
+ *mp = (struct mbuf *)0;
+ } else {
+ MFREE(m, so->so_rcv.sb_mb);
+ m = so->so_rcv.sb_mb;
+ }
+ if (m)
+ m->m_nextpkt = nextrecord;
+ }
+ } else {
+ if (flags & MSG_PEEK)
+ moff += len;
+ else {
+ if (mp)
+ *mp = m_copym(m, 0, len, M_TRYWAIT);
+ m->m_data += len;
+ m->m_len -= len;
+ so->so_rcv.sb_cc -= len;
+ }
+ }
+ if (so->so_oobmark) {
+ if ((flags & MSG_PEEK) == 0) {
+ so->so_oobmark -= len;
+ if (so->so_oobmark == 0) {
+ so->so_state |= SS_RCVATMARK;
+ break;
+ }
+ } else {
+ offset += len;
+ if (offset == so->so_oobmark)
+ break;
+ }
+ }
+ if (flags & MSG_EOR)
+ break;
+ /*
+ * If the MSG_WAITALL flag is set (for non-atomic socket),
+ * we must not quit until "uio->uio_resid == 0" or an error
+ * termination. If a signal/timeout occurs, return
+ * with a short count but without error.
+ * Keep sockbuf locked against other readers.
+ */
+ while (flags & MSG_WAITALL && m == 0 && uio->uio_resid > 0 &&
+ !sosendallatonce(so) && !nextrecord) {
+ if (so->so_error || so->so_state & SS_CANTRCVMORE)
+ break;
+ /*
+ * Notify the protocol that some data has been
+ * drained before blocking.
+ */
+ if (pr->pr_flags & PR_WANTRCVD && so->so_pcb)
+ (*pr->pr_usrreqs->pru_rcvd)(so, flags);
+ error = sbwait(&so->so_rcv);
+ if (error) {
+ sbunlock(&so->so_rcv);
+ splx(s);
+ return (0);
+ }
+ m = so->so_rcv.sb_mb;
+ if (m)
+ nextrecord = m->m_nextpkt;
+ }
+ }
+
+ if (m && pr->pr_flags & PR_ATOMIC) {
+ flags |= MSG_TRUNC;
+ if ((flags & MSG_PEEK) == 0)
+ (void) sbdroprecord(&so->so_rcv);
+ }
+ if ((flags & MSG_PEEK) == 0) {
+ if (m == 0)
+ so->so_rcv.sb_mb = nextrecord;
+ if (pr->pr_flags & PR_WANTRCVD && so->so_pcb)
+ (*pr->pr_usrreqs->pru_rcvd)(so, flags);
+ }
+ if (orig_resid == uio->uio_resid && orig_resid &&
+ (flags & MSG_EOR) == 0 && (so->so_state & SS_CANTRCVMORE) == 0) {
+ sbunlock(&so->so_rcv);
+ splx(s);
+ goto restart;
+ }
+
+ if (flagsp)
+ *flagsp |= flags;
+release:
+ sbunlock(&so->so_rcv);
+ splx(s);
+ return (error);
+}
diff --git a/sys/security/lomac/kernel_socket.h b/sys/security/lomac/kernel_socket.h
new file mode 100644
index 0000000..4343c19
--- /dev/null
+++ b/sys/security/lomac/kernel_socket.h
@@ -0,0 +1,45 @@
+/*-
+ * Copyright (c) 2001 Networks Associates Technologies, Inc.
+ * All rights reserved.
+ *
+ * This software was developed for the FreeBSD Project 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.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * 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.
+ *
+ * $Id$
+ * $FreeBSD$
+ */
+
+#ifndef _KERNEL_SOCKET_H_
+#define _KERNEL_SOCKET_H_
+
+int lomac_initialize_sockets( void );
+int lomac_uninitialize_sockets( void );
+
+#endif /* _KERNEL_SOCKET_H_ */
+
diff --git a/sys/security/lomac/kernel_util.c b/sys/security/lomac/kernel_util.c
new file mode 100644
index 0000000..b80bdfd
--- /dev/null
+++ b/sys/security/lomac/kernel_util.c
@@ -0,0 +1,696 @@
+/*-
+ * Copyright (c) 2001 Networks Associates Technologies, Inc.
+ * Copyright (c) 1982, 1986, 1989, 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ * (c) UNIX System Laboratories, Inc.
+
+ * This software was developed for the FreeBSD Project 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.
+ *
+ * All or some portions of this file are derived from material licensed
+ * to the University of California by American Telephone and Telegraph
+ * Co. or Unix System Laboratories, Inc. and are reproduced herein with
+ * the permission of UNIX System Laboratories, 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. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * 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.
+ *
+ * $Id$
+ * $FreeBSD$
+ */
+
+#include <sys/param.h>
+#include <sys/proc.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/signalvar.h>
+#include <sys/sx.h>
+#include <sys/syscall.h>
+#include <sys/sysent.h>
+#include <sys/sysproto.h>
+#include <sys/systm.h>
+#include <sys/linker.h>
+#include <sys/mount.h>
+#include <sys/mman.h>
+#include <sys/dirent.h>
+#include <sys/namei.h>
+#include <sys/uio.h>
+#include <sys/unistd.h>
+
+#include <vm/vm.h>
+#include <vm/vm_extern.h>
+#include <vm/vm_kern.h>
+
+#include "kernel_interface.h"
+#include "kernel_util.h"
+#include "kernel_mediate.h"
+#include "kernel_monitor.h"
+#include "lomacfs.h"
+
+#include "syscall_gate.h"
+
+#define AS(name) (sizeof(struct name) / sizeof(register_t))
+
+int
+each_proc(int (*iter)(struct proc *p)) {
+ struct proc *p;
+ int error = 0;
+
+ sx_slock(&allproc_lock);
+ LIST_FOREACH(p, &allproc, p_list) {
+ error = (*iter)(p);
+ if (error)
+ goto out;
+ }
+out:
+ sx_sunlock(&allproc_lock);
+ return (error);
+}
+
+static int
+initialize_proc(struct proc *p) {
+ lattr_t lattr = { LOMAC_HIGHEST_LEVEL, 0 };
+
+ init_subject_lattr(p, &lattr);
+ return (0);
+}
+
+static void
+lomac_at_fork(struct proc *parent, struct proc *p, int flags) {
+
+ if ((flags & RFMEM) == 0) {
+ lattr_t parent_lattr;
+
+ get_subject_lattr(parent, &parent_lattr);
+ init_subject_lattr(p, &parent_lattr);
+ }
+}
+
+static int
+lomac_proc_candebug(struct proc *p1, struct proc *p2) {
+ lattr_t lattr;
+
+ get_subject_lattr(p1, &lattr);
+ if (mediate_subject_level_subject("debug", p1, lattr.level, p2))
+ return (0);
+ else
+ return (EPERM);
+}
+
+static int
+lomac_proc_cansched(struct proc *p1, struct proc *p2) {
+ lattr_t lattr;
+
+ get_subject_lattr(p1, &lattr);
+ if (mediate_subject_level_subject("sched", p1, lattr.level, p2))
+ return (0);
+ else
+ return (EPERM);
+}
+
+static int
+lomac_proc_cansignal(struct proc *p1, struct proc *p2, int signum) {
+ lattr_t lattr;
+
+ get_subject_lattr(p1, &lattr);
+ /*
+ * Always allow signals to init(8) (necessary to shut down).
+ */
+ if (p2->p_pid == 1 ||
+ mediate_subject_level_subject("signal", p1, lattr.level, p2))
+ return (0);
+ else
+ return (EPERM);
+}
+
+
+int
+lomac_initialize_procs(void) {
+ int error;
+
+#ifdef P_CAN_HOOKS
+ can_hooks_lock();
+ (void)p_candebug_hook(lomac_proc_candebug);
+ (void)p_cansignal_hook(lomac_proc_cansignal);
+ (void)p_cansched_hook(lomac_proc_cansched);
+ can_hooks_unlock();
+#endif
+ error = at_fork(lomac_at_fork);
+ if (error)
+ return (error);
+ return (each_proc(&initialize_proc));
+}
+
+int
+lomac_uninitialize_procs(void) {
+
+ rm_at_fork(lomac_at_fork);
+ return (0);
+}
+
+extern int (*old_execve)(struct thread *, struct execve_args *);
+
+int
+execve(struct thread *td, struct execve_args *uap) {
+ lattr_t lattr, textattr;
+ struct vmspace *oldvmspace;
+ struct proc *p;
+ int error;
+
+ p = td->td_proc;
+ get_subject_lattr(p, &lattr);
+ oldvmspace = p->p_vmspace;
+ error = old_execve(td, uap);
+ if (error == 0) {
+ lomac_object_t lobj;
+
+ lobj.lo_type = VISLOMAC(p->p_textvp) ? LO_TYPE_LVNODE :
+ LO_TYPE_UVNODE;
+ lobj.lo_object.vnode = p->p_textvp;
+ get_object_lattr(&lobj, &textattr);
+ /*
+ * Install the executable's relevant attributes into the
+ * process.
+ */
+ lattr.flags |= textattr.flags &
+ (LOMAC_ATTR_NODEMOTE | LOMAC_ATTR_NONETDEMOTE);
+ if (p->p_vmspace != oldvmspace)
+ init_subject_lattr(p, &lattr);
+ else
+ set_subject_lattr(p, lattr);
+ mtx_lock(&Giant);
+ (void)monitor_read_object(p, &lobj);
+ mtx_unlock(&Giant);
+ }
+ return (error);
+}
+
+const char *linker_basename(const char* path);
+int linker_load_module(const char *kldname, const char *modname,
+ struct linker_file *parent, struct mod_depend *verinfo,
+ struct linker_file **lfpp);
+
+MALLOC_DECLARE(M_LINKER);
+
+/*
+ * MPSAFE
+ */
+int
+kldload(struct thread* td, struct kldload_args* uap)
+{
+ char *kldname, *modname;
+ char *pathname = NULL;
+ linker_file_t lf;
+ int error = 0;
+
+ td->td_retval[0] = -1;
+
+ if (securelevel > 0) /* redundant, but that's OK */
+ return EPERM;
+
+ mtx_lock(&Giant);
+
+ if ((error = suser_td(td)) != 0)
+ goto out;
+
+ pathname = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
+ if ((error = copyinstr(SCARG(uap, file), pathname, MAXPATHLEN, NULL)) != 0)
+ goto out;
+ if (!mediate_subject_at_level("kldload", td->td_proc,
+ LOMAC_HIGHEST_LEVEL)) {
+ error = EPERM;
+ goto out;
+ }
+
+ /*
+ * If path do not contain qualified name or any dot in it (kldname.ko, or
+ * kldname.ver.ko) treat it as interface name.
+ */
+ if (index(pathname, '/') || index(pathname, '.')) {
+ kldname = pathname;
+ modname = NULL;
+ } else {
+ kldname = NULL;
+ modname = pathname;
+ }
+ error = linker_load_module(kldname, modname, NULL, NULL, &lf);
+ if (error)
+ goto out;
+
+ lf->userrefs++;
+ td->td_retval[0] = lf->id;
+
+out:
+ if (pathname)
+ free(pathname, M_TEMP);
+ mtx_unlock(&Giant);
+ return (error);
+}
+
+
+#ifdef __i386__
+#include <machine/sysarch.h>
+
+extern int (*old_sysarch)(struct thread *, void *);
+
+int
+sysarch(struct thread *td, struct sysarch_args *uap) {
+ switch (uap->op) {
+ case I386_SET_IOPERM:
+ if (!mediate_subject_at_level("ioperm", td->td_proc,
+ LOMAC_HIGHEST_LEVEL))
+ return (EPERM);
+ default:
+ return (old_sysarch(td, uap));
+ }
+}
+#endif
+
+extern int lomac_mmap(struct proc *, struct mmap_args *);
+
+/*
+ * Mount a file system.
+ */
+#ifndef _SYS_SYSPROTO_H_
+struct mount_args {
+ char *type;
+ char *path;
+ int flags;
+ caddr_t data;
+};
+#endif
+/* ARGSUSED */
+int
+mount(td, uap)
+ struct thread *td;
+ struct mount_args /* {
+ syscallarg(char *) type;
+ syscallarg(char *) path;
+ syscallarg(int) flags;
+ syscallarg(caddr_t) data;
+ } */ *uap;
+{
+ char *fstype;
+ char *fspath;
+ int error;
+
+ fstype = malloc(MFSNAMELEN, M_TEMP, M_WAITOK | M_ZERO);
+ fspath = malloc(MNAMELEN, M_TEMP, M_WAITOK | M_ZERO);
+
+ /*
+ * vfs_mount() actually takes a kernel string for `type' and
+ * `path' now, so extract them.
+ */
+ error = copyinstr(SCARG(uap, type), fstype, MFSNAMELEN, NULL);
+ if (error)
+ goto finish;
+ error = copyinstr(SCARG(uap, path), fspath, MNAMELEN, NULL);
+ if (error)
+ goto finish;
+ if (!mediate_subject_at_level("mount", td->td_proc,
+ LOMAC_HIGHEST_LEVEL)) {
+ error = EPERM;
+ goto finish;
+ }
+ error = vfs_mount(td, fstype, fspath, SCARG(uap, flags),
+ SCARG(uap, data));
+finish:
+ free(fstype, M_TEMP);
+ free(fspath, M_TEMP);
+ return (error);
+}
+
+/*
+ * Unmount a file system.
+ *
+ * Note: unmount takes a path to the vnode mounted on as argument,
+ * not special file (as before).
+ */
+#ifndef _SYS_SYSPROTO_H_
+struct unmount_args {
+ char *path;
+ int flags;
+};
+#endif
+/* ARGSUSED */
+int
+unmount(td, uap)
+ struct thread *td;
+ register struct unmount_args /* {
+ syscallarg(char *) path;
+ syscallarg(int) flags;
+ } */ *uap;
+{
+ register struct vnode *vp;
+ struct mount *mp;
+ int error;
+ struct nameidata nd;
+
+ NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
+ SCARG(uap, path), td);
+ if ((error = namei(&nd)) != 0)
+ return (error);
+ vp = nd.ni_vp;
+ NDFREE(&nd, NDF_ONLY_PNBUF);
+ mp = vp->v_mount;
+
+ /*
+ * Only root, or the user that did the original mount is
+ * permitted to unmount this filesystem.
+ */
+ if (!mediate_subject_at_level("unmount", td->td_proc,
+ LOMAC_HIGHEST_LEVEL) ||
+ ((mp->mnt_stat.f_owner != td->td_proc->p_ucred->cr_uid) &&
+ (error = suser_td(td)))) {
+ vput(vp);
+ return (error);
+ }
+
+ /*
+ * Don't allow unmounting the root file system.
+ */
+ if (mp->mnt_flag & MNT_ROOTFS) {
+ vput(vp);
+ return (EINVAL);
+ }
+
+ /*
+ * Must be the root of the filesystem
+ */
+ if ((vp->v_flag & VROOT) == 0) {
+ vput(vp);
+ return (EINVAL);
+ }
+ vput(vp);
+ return (dounmount(mp, SCARG(uap, flags), td));
+}
+
+static struct syscall_override {
+ int offset;
+ sy_call_t *call;
+ int narg;
+ int mpsafe;
+} syscall_overrides[] = {
+ { SYS_mmap, (sy_call_t *)mmap, AS(mmap_args), 1 },
+ { SYS_execve, (sy_call_t *)execve, AS(execve_args), 1 },
+ { SYS_kldload, (sy_call_t *)kldload, AS(kldload_args), 1 },
+ { SYS_mount, (sy_call_t *)mount, AS(mount_args), 0 },
+ { SYS_unmount, (sy_call_t *)unmount, AS(unmount_args), 0 },
+#ifdef __i386__
+ { SYS_sysarch, (sy_call_t *)sysarch, AS(sysarch_args), 1 }
+#endif
+};
+
+int
+lomac_initialize_syscalls(void) {
+ int error, i;
+
+ for (i = 0;
+ i < sizeof(syscall_overrides) / sizeof(syscall_overrides[0]); i++) {
+ struct syscall_override *so = &syscall_overrides[i];
+
+ error = syscall_gate_register(so->offset, so->call, so->narg,
+ so->mpsafe);
+ if (error) {
+ while (--i >= 0)
+ syscall_gate_deregister(
+ syscall_overrides[i].offset);
+ return (error);
+ }
+ }
+ return (0);
+}
+
+int
+lomac_uninitialize_syscalls(void) {
+ int i;
+
+ for (i = 0;
+ i < sizeof(syscall_overrides) / sizeof(syscall_overrides[0]); i++)
+ syscall_gate_deregister(syscall_overrides[i].offset);
+ return (0);
+}
+
+/* This memory is shared by all lomac_do_recwd() calls, in sequence. */
+static char *pathmem;
+#define DIRENTMEM_SIZE (64 << 10) /* 64KB is good, I guess! */
+static char *direntmem;
+
+static int
+lomac_dirents_searchbyid(struct vnode *dvp, struct dirent *dp,
+ struct dirent *enddp, const struct vattr *vap, struct dirent **retdp)
+{
+ struct vattr pvattr;
+ struct componentname cnp;
+ struct thread *td = curthread;
+ struct ucred *ucred = td->td_ucred;
+ struct vnode *vp;
+ int error;
+
+ *retdp = NULL;
+ for (; dp != enddp; dp = (struct dirent *)((char *)dp + dp->d_reclen)) {
+ cnp.cn_nameiop = LOOKUP;
+ cnp.cn_flags = LOCKPARENT | ISLASTCN | NOFOLLOW;
+ cnp.cn_thread = td;
+ cnp.cn_cred = ucred;
+ cnp.cn_nameptr = dp->d_name;
+ cnp.cn_namelen = dp->d_namlen;
+
+ error = VOP_LOOKUP(dvp, &vp, &cnp);
+ if (error)
+ return (error);
+ error = VOP_GETATTR(vp, &pvattr, ucred, td);
+ if (vp != dvp)
+ (void)vput(vp);
+ else
+ vrele(vp); /* if looking up "." */
+ if (error)
+ return (error);
+ if (pvattr.va_fsid == vap->va_fsid &&
+ pvattr.va_fileid == vap->va_fileid) {
+ *retdp = dp;
+ break;
+ }
+ }
+ return (0);
+}
+
+static int
+lomac_getcwd(
+ struct thread *td,
+ char *buf,
+ size_t buflen,
+ char **bufret
+) {
+ struct vattr cvattr;
+ char *bp;
+ int error, i, slash_prefixed;
+ struct filedesc *fdp;
+ struct vnode *vp, *startvp, *dvp;
+
+ if (buflen < 2)
+ return (EINVAL);
+ if (buflen > MAXPATHLEN)
+ buflen = MAXPATHLEN;
+ bp = buf;
+ bp += buflen - 1;
+ *bp = '\0';
+ fdp = td->td_proc->p_fd;
+ slash_prefixed = 0;
+#if defined(LOMAC_DEBUG_RECWD)
+ printf("lomac_getcwd for %d:\n", td->td_proc->p_pid);
+#endif
+ startvp = fdp->fd_cdir;
+ vref(startvp);
+ for (vp = startvp; vp != rootvnode; vp = dvp) {
+ struct iovec diov = {
+ direntmem,
+ DIRENTMEM_SIZE
+ };
+ struct uio duio = {
+ &diov,
+ 1,
+ 0,
+ DIRENTMEM_SIZE,
+ UIO_SYSSPACE,
+ UIO_READ,
+ curthread
+ };
+ struct dirent *dp;
+ int direof;
+
+ if (vp->v_flag & VROOT) {
+ if (vp->v_mount == NULL) /* forced unmount */
+ return (EBADF);
+ dvp = vp->v_mount->mnt_vnodecovered;
+ continue;
+ }
+ dvp = vp->v_dd;
+ if (vp == dvp)
+ break;
+ /*
+ * Utilize POSIX requirement of files having same
+ * st_dev and st_ino to be the same file, in our
+ * case with vattr.va_fsid and vattr.va_fileid.
+ */
+ error = vget(vp, LK_EXCLUSIVE, curthread);
+ if (error)
+ goto out2;
+ error = VOP_GETATTR(vp, &cvattr, curthread->td_ucred,
+ curthread);
+ if (error)
+ goto out2;
+ (void)vput(vp);
+ error = vget(dvp, LK_EXCLUSIVE, curthread);
+ if (error)
+ goto out2;
+ for (direof = 0; !direof;) {
+ error = VOP_READDIR(dvp, &duio,
+ curthread->td_ucred, &direof, NULL, NULL);
+ if (error)
+ break;
+ error = lomac_dirents_searchbyid(dvp,
+ (struct dirent *)direntmem,
+ (struct dirent *)(direntmem +
+ DIRENTMEM_SIZE - duio.uio_resid),
+ &cvattr,
+ &dp);
+ if (error)
+ break;
+ if (dp != NULL) {
+ (void)vput(dvp);
+#if defined(LOMAC_DEBUG_RECWD)
+ printf("\tdirent component: \"%.*s\"\n",
+ dp->d_namlen, dp->d_name);
+#endif
+ for (i = dp->d_namlen - 1; i >= 0; i--)
+ if (bp == buf)
+ return (ENOMEM);
+ else
+ *--bp = dp->d_name[i];
+ goto nextcomp;
+ }
+ diov.iov_base = direntmem;
+ diov.iov_len = DIRENTMEM_SIZE;
+ duio.uio_resid = DIRENTMEM_SIZE;
+ }
+ if (direof)
+ error = ENOENT;
+ (void)vput(dvp);
+ out2:
+#if defined(LOMAC_DEBUG_RECWD)
+ printf("backup dirent lookup problem: %d\n", error);
+#endif
+ goto out;
+ nextcomp:
+ if (bp == buf)
+ return (ENOMEM);
+ *--bp = '/';
+ slash_prefixed = 1;
+ }
+ if (!slash_prefixed) {
+ if (bp == buf)
+ return (ENOMEM);
+ *--bp = '/';
+ }
+ error = 0;
+ *bufret = bp;
+out:
+ vrele(startvp);
+ return (error);
+}
+
+static int
+lomac_do_recwd(struct proc *p) {
+ struct nameidata nd;
+ struct filedesc *fdp = curthread->td_proc->p_fd;
+ struct thread *td = &p->p_thread;
+ char *nbuf;
+ struct vnode *cdir, *rdir, *vp;
+ int error;
+
+ if (p == curthread->td_proc)
+ return (0);
+ PROC_LOCK(p);
+ if (p->p_flag & P_SYSTEM) {
+ PROC_UNLOCK(p);
+ return (0);
+ }
+ PROC_UNLOCK(p);
+ error = lomac_getcwd(td, pathmem, MAXPATHLEN, &nbuf);
+ if (error) {
+#if defined(LOMAC_DEBUG_RECWD)
+ printf("lomac: recwd() failure, lomac_getcwd() == %d\n",
+ error);
+#endif
+ return (0);
+ }
+ rdir = fdp->fd_rdir;
+ fdp->fd_rdir = rootvnode;
+ vref(fdp->fd_rdir);
+ NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE,
+ nbuf, curthread);
+ error = namei(&nd);
+ vrele(fdp->fd_rdir);
+ fdp->fd_rdir = rdir;
+ if (error == 0) {
+ vp = nd.ni_vp;
+ if (vp->v_type != VDIR)
+ error = ENOTDIR;
+ else
+ error = VOP_ACCESS(vp, VEXEC, td->td_proc->p_ucred,
+ curthread);
+ if (error)
+ vput(vp);
+ else {
+ NDFREE(&nd, NDF_ONLY_PNBUF);
+ fdp = p->p_fd;
+ cdir = fdp->fd_cdir;
+ fdp->fd_cdir = vp;
+ vrele(cdir);
+ VOP_UNLOCK(vp, 0, curthread);
+ }
+ }
+#if defined(LOMAC_DEBUG_RECWD)
+ printf("\trecwd() to \"%.*s\" == %d\n",
+ MAXPATHLEN, nbuf, error);
+#endif
+ return (0);
+}
+
+int
+lomac_initialize_cwds(void) {
+ int error;
+
+ pathmem = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
+ direntmem = malloc(DIRENTMEM_SIZE, M_TEMP, M_WAITOK);
+ mtx_lock(&Giant);
+ error = each_proc(lomac_do_recwd);
+ mtx_unlock(&Giant);
+ free(pathmem, M_TEMP);
+ free(direntmem, M_TEMP);
+ return (error);
+}
diff --git a/sys/security/lomac/kernel_util.h b/sys/security/lomac/kernel_util.h
new file mode 100644
index 0000000..f3480ed
--- /dev/null
+++ b/sys/security/lomac/kernel_util.h
@@ -0,0 +1,64 @@
+/*-
+ * Copyright (c) 2001 Networks Associates Technologies, Inc.
+ * All rights reserved.
+ *
+ * This software was developed for the FreeBSD Project 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.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * 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.
+ *
+ * $Id$
+ * $FreeBSD$
+ */
+
+#ifndef KERNEL_UTIL_H
+#define KERNEL_UTIL_H
+
+/*
+ * Iterate through each proc, locking it and calling iter.
+ * Short-circuit and return an error if the iterator ever returns one.
+ */
+int each_proc(int (*iter)(struct proc *p));
+
+/*
+ * Set the initial level on each proc, register at_fork().
+ */
+int lomac_initialize_procs(void);
+
+/*
+ * Unregister at_fork().
+ */
+int lomac_uninitialize_procs(void);
+
+int lomac_initialize_cwds(void);
+
+int lomac_initialize_syscalls(void);
+int lomac_uninitialize_syscalls(void);
+
+int lomac_initialize_vm(void);
+int lomac_uninitialize_vm(void);
+#endif /* KERNEL_UTIL_H */
diff --git a/sys/security/lomac/lomac.h b/sys/security/lomac/lomac.h
new file mode 100644
index 0000000..b891fb1
--- /dev/null
+++ b/sys/security/lomac/lomac.h
@@ -0,0 +1,114 @@
+/*-
+ * Copyright (c) 2001 Networks Associates Technologies, Inc.
+ * All rights reserved.
+ *
+ * This software was developed for the FreeBSD Project 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.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * 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 LOMAC_H_
+#define LOMAC_H_
+
+typedef enum {
+ LOMAC_LOWEST_LEVEL = 1,
+ LOMAC_HIGHEST_LEVEL = 2
+} level_t;
+
+
+typedef struct {
+ level_t level; /* level (an integer range) */
+ unsigned int flags; /* category flags */
+} lattr_t; /* lomac attribute structure type */
+
+
+/* lomac_must_demote()
+ *
+ * in: actor - attributes of a subject that has or will perform an
+ * operation that may require LOMAC to demote it.
+ * target - attributes of the object that is or was the operand.
+ * out: nothing
+ * return: value condition
+ * ----- ---------
+ * 0 LOMAC should not demote the subject
+ * 1 LOMAC should demote the subject
+ *
+ * This function is a predicate which decides whether or not LOMAC should
+ * demote the subject with attributes `actor' after it performs an operation
+ * (probably some kind of a read operation) on the object with attributes
+ * `target'.
+ *
+ */
+
+static __inline int
+lomac_must_demote(const lattr_t *actor, const lattr_t *target) {
+ return (actor->level > target->level);
+}
+
+
+/* lomac_must_deny()
+ *
+ * in: actor - attributes of a subject that wants to perform some
+ * operation that requires LOMAC to make an allow/deny
+ * decision.
+ * target - attributes of the subject or object the above subject
+ * will operate upon.
+ * out: nothing
+ * return: value condition
+ * ----- ---------
+ * 0 LOMAC should allow the operation
+ * 1 LOMAC should deny the operation
+ *
+ * This function is a predicate which decides whether or not LOMAC should
+ * allow the subject with attributes `actor' to perform some operation
+ * (probably some kind of write or kill operation) on the subject or object
+ * with attributes `target'.
+ *
+ * The flags are two words: the low word is to be used for categories,
+ * and the high word is meant to hold implementation-dependent flags that
+ * are not category-related.
+ *
+ */
+
+static __inline int
+lomac_must_deny(const lattr_t *actor, const lattr_t *target) {
+
+ if (actor->level >= target->level)
+ return 0; /* allow */
+ if (target->flags & 0xffff) {
+ if ((actor->flags & target->flags & 0xffff) ==
+ (target->flags & 0xffff)) {
+ return 0; /* allow */
+ }
+ }
+ return 1; /* deny */
+}
+
+#endif /* LOMAC_H */
diff --git a/sys/security/lomac/lomacfs.h b/sys/security/lomac/lomacfs.h
new file mode 100644
index 0000000..b144146
--- /dev/null
+++ b/sys/security/lomac/lomacfs.h
@@ -0,0 +1,115 @@
+/*-
+ * Copyright (c) 2001 Networks Associates Technologies, Inc.
+ * All rights reserved.
+ *
+ * This software was developed for the FreeBSD Project 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.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * 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.
+ *
+ * $Id$
+ * $FreeBSD$
+ */
+
+#ifndef LOMACFS_H
+#define LOMACFS_H
+
+#include <sys/param.h>
+#include <sys/malloc.h>
+#include <sys/queue.h>
+#include <sys/vnode.h>
+#include <sys/mount.h>
+
+#include "kernel_interface.h"
+
+struct lomac_mount {
+ struct vnode *lm_rootvp; /* singly-ref'd root after mount() */
+#define LM_TOOKROOT 0x0001
+ unsigned int lm_flags;
+};
+
+/*
+ * This is the structure associated with v_data on all LOMACFS vnodes.
+ */
+struct lomac_node {
+ struct vnode *ln_vp; /* vnode back-pointer */
+ struct vnode *ln_lowervp; /* shadowed vnode (ref'd or NULL) */
+#define LN_LEVEL_MASK 0x0003
+#define LN_LOWEST_LEVEL 0x0001
+#define LN_SUBJ_LEVEL 0x0002 /* placeholder before inheriting */
+#define LN_HIGHEST_LEVEL 0x0003
+#define LN_INHERIT_MASK 0x001c
+#define LN_INHERIT_LOW 0x0004 /* children start with a low level */
+#define LN_INHERIT_HIGH 0x0008 /* children start with a high level */
+#define LN_INHERIT_SUBJ 0x0010 /* children inherit subject's level */
+#define LN_ATTR_MASK 0x01e0
+#define LN_ATTR_LOWWRITE 0x0020 /* lower levels may write to */
+#define LN_ATTR_LOWNOOPEN 0x0040 /* lower levels may not open */
+#define LN_ATTR_NONETDEMOTE 0x0080 /* will not demote on net read */
+#define LN_ATTR_NODEMOTE 0x0100 /* subject won't demote on other read */
+ u_int ln_flags;
+ /* What's the last node explicitly specifying policy for this? */
+ struct lomac_node_entry *ln_underpolicy;
+ /* If non-NULL, this corresponds 1:1 to a specific PLM node entry. */
+ struct lomac_node_entry *ln_entry;
+#if defined(LOMAC_DEBUG_INCNAME)
+ char ln_name[MAXPATHLEN]; /* final component name */
+#endif
+};
+
+/*
+ * This is the "placeholder" structure initialized from the PLM that
+ * holds the level information for all named objects.
+ */
+struct lomac_node_entry {
+ SLIST_HEAD(lomac_node_entry_head, lomac_node_entry) ln_children;
+ SLIST_ENTRY(lomac_node_entry) ln_chain; /* chain of current level */
+ /* continuing with the LN_* flags above */
+#define LN_CHILD_ATTR_SHIFT 4 /* lshift from attr -> child attr */
+#define LN_CHILD_ATTR_MASK 0x1e00
+#define LN_CHILD_ATTR_LOWWRITE 0x0200 /* lower levels may write to */
+#define LN_CHILD_ATTR_LOWNOOPEN 0x0400 /* lower levels may not open */
+#define LN_CHILD_ATTR_NONETDEMOTE 0x0800 /* will not demote on net read */
+#define LN_CHILD_ATTR_NODEMOTE 0x1000 /* subject won't demote on other read */
+ u_int ln_flags;
+ char *ln_name; /* last component name (to search) */
+ const char *ln_path; /* in "stable" storage */
+};
+
+#define VTOLOMAC(vp) ((struct lomac_node *)(vp)->v_data)
+#define VTOLVP(vp) VTOLOMAC(vp)->ln_lowervp
+#define VFSTOLOMAC(mp) ((struct lomac_mount *)mp->mnt_data)
+#define VISLOMAC(vp) (vp->v_op == lomacfs_vnodeop_p)
+
+int lomacfs_node_alloc(struct mount *mp, struct componentname *cnp,
+ struct vnode *dvp, struct vnode *lowervp, struct vnode **vpp);
+
+MALLOC_DECLARE(M_LOMACFS);
+extern vop_t **lomacfs_vnodeop_p;
+extern struct lomac_node_entry lomac_node_entry_root;
+
+#endif /* LOMACFS_H */
diff --git a/sys/security/lomac/lomacfs_subr.c b/sys/security/lomac/lomacfs_subr.c
new file mode 100644
index 0000000..fd7df03
--- /dev/null
+++ b/sys/security/lomac/lomacfs_subr.c
@@ -0,0 +1,127 @@
+/*-
+ * Copyright (c) 2001 Networks Associates Technologies, Inc.
+ * All rights reserved.
+ *
+ * This software was developed for the FreeBSD Project 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.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * 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.
+ *
+ * $Id$
+ * $FreeBSD$
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/namei.h>
+
+#include <vm/vm.h>
+#include <vm/vm_extern.h>
+
+#include "lomacfs.h"
+#include "kernel_plm.h"
+
+int
+lomacfs_node_alloc(struct mount *mp, struct componentname *cnp,
+ struct vnode *dvp, struct vnode *lowervp, struct vnode **vpp) {
+ lomac_object_t lobj;
+ struct thread *td = curthread;
+ struct vnode *vp;
+ struct lomac_node *lp;
+ lattr_t subjlattr, objlattr;
+ int error;
+
+ KASSERT((cnp == NULL) == (dvp == NULL),
+ ("lomacfs_node_alloc: dvp and cnp do not match"));
+ lp = malloc(sizeof(*lp), M_LOMACFS, M_WAITOK);
+ if (dvp != NULL) {
+ error = cache_lookup(dvp, vpp, cnp);
+ if (error == -1) { /* lost the race; return EEXIST and the vp */
+ vput(lowervp);
+ error = vget(*vpp, LK_EXCLUSIVE, td);
+ free(lp, M_LOMACFS);
+ if (error) {
+ *vpp = NULL;
+ return (error);
+ } else
+ return (EEXIST);
+ }
+ }
+ error = getnewvnode(VT_NULL, mp, lomacfs_vnodeop_p, vpp);
+ if (error) {
+ vput(lowervp);
+ free(lp, M_LOMACFS);
+ return (error);
+ }
+ vp = *vpp;
+
+ vp->v_type = lowervp != NULL ? lowervp->v_type : VBAD;
+ if (vp->v_type == VCHR)
+ vp->v_rdev = lowervp->v_rdev;
+ vp->v_data = lp;
+ lp->ln_vp = vp;
+ lp->ln_lowervp = lowervp;
+ if (lowervp != NULL)
+ vhold(lowervp);
+ get_subject_lattr(curthread->td_proc, &subjlattr);
+ lp->ln_flags = 0;
+ lomac_plm_init_lomacfs_vnode(dvp, vp, cnp, &subjlattr);
+ /* retrieve the just-initialized attributes */
+ lobj.lo_type = LO_TYPE_LVNODE;
+ lobj.lo_object.vnode = vp;
+ get_object_lattr(&lobj, &objlattr);
+ /* propogate the lattr to the underlying vnode */
+ lobj.lo_type = LO_TYPE_UVNODE;
+ lobj.lo_object.vnode = lowervp;
+ set_object_lattr(&lobj, objlattr);
+#if defined(LOMAC_DEBUG_INCNAME)
+ if (cnp == NULL)
+ strncpy(lp->ln_name, "/", sizeof(lp->ln_name));
+ else {
+ strncpy(lp->ln_name, cnp->cn_nameptr, cnp->cn_namelen);
+ lp->ln_name[cnp->cn_namelen] = '\0';
+ }
+#endif
+ error = vn_lock(vp, LK_EXCLUSIVE | LK_RETRY | LK_THISLAYER, td);
+ if (error)
+ panic("lomacfs_node_alloc: can't lock new vnode\n");
+ if (cnp == NULL)
+ vp->v_flag |= VROOT;
+ else if (cnp->cn_flags & MAKEENTRY)
+ cache_enter(dvp, vp, cnp);
+
+#if defined(LOMAC_DEBUG_NODE_ALLOC)
+ printf("lomacfs: made vp %p for lvp %p \"%.*s\" in dvp %p from %s\n",
+ vp, lowervp, cnp ? (int)cnp->cn_namelen : 0,
+ cnp ? cnp->cn_nameptr : "", dvp,
+ lowervp != NULL ? lowervp->v_mount->mnt_stat.f_mntonname : "");
+#endif
+
+ return (0);
+}
diff --git a/sys/security/lomac/lomacfs_vfsops.c b/sys/security/lomac/lomacfs_vfsops.c
new file mode 100644
index 0000000..c7ee93a
--- /dev/null
+++ b/sys/security/lomac/lomacfs_vfsops.c
@@ -0,0 +1,199 @@
+/*-
+ * Copyright (c) 2001 Networks Associates Technologies, Inc.
+ * All rights reserved.
+ *
+ * This software was developed for the FreeBSD Project 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.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * 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.
+ *
+ * $Id$
+ * $FreeBSD$
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/proc.h>
+#include <sys/module.h>
+#include <sys/mount.h>
+#include <sys/namei.h>
+#include <sys/vnode.h>
+
+#include "lomacfs.h"
+#include "kernel_mediate.h"
+
+MALLOC_DEFINE(M_LOMACFS, "LOMACFS", "LOMAC filesystem objects");
+
+static int lomacfs_mount(struct mount *mp, char *path, caddr_t data,
+ struct nameidata *ndp, struct thread *td);
+static int lomacfs_statfs(struct mount *mp, struct statfs *sbp,
+ struct thread *td);
+static int lomacfs_unmount(struct mount *mp, int mntflags, struct thread *td);
+
+static int
+lomacfs_mount(struct mount *mp, char *path, caddr_t data,
+ struct nameidata *ndp, struct thread *td) {
+
+ if (mp->mnt_flag & MNT_UPDATE || VISLOMAC(mp->mnt_vnodecovered))
+ return (EOPNOTSUPP);
+
+ mp->mnt_flag |= MNT_LOCAL;
+ mp->mnt_flag &= ~MNT_RDONLY;
+ mp->mnt_data = malloc(sizeof(struct lomac_mount), M_LOMACFS,
+ M_WAITOK | M_ZERO);
+ vfs_getnewfsid(mp);
+
+ strncpy(mp->mnt_stat.f_mntfromname, "lomacfs", MNAMELEN);
+ (void)lomacfs_statfs(mp, &mp->mnt_stat, td);
+
+ /*
+ * Keep around an extra ref for dounmount() to vrele() after the
+ * VFS_UNMOUNT()... (who knows...)
+ */
+ vref(mp->mnt_vnodecovered);
+ if (VOP_ISLOCKED(mp->mnt_vnodecovered, NULL))
+ VOP_UNLOCK(mp->mnt_vnodecovered, 0, td);
+
+ return (0);
+}
+
+static int
+lomacfs_statfs(struct mount *mp, struct statfs *sbp, struct thread *td) {
+ struct statfs tmpstat;
+ int error;
+
+ bzero(&tmpstat, sizeof(tmpstat));
+
+ error = VFS_STATFS(mp->mnt_vnodecovered->v_mount, &tmpstat, td);
+ if (error)
+ return (error);
+
+ sbp->f_type = tmpstat.f_type;
+ sbp->f_flags = tmpstat.f_flags;
+ sbp->f_bsize = tmpstat.f_bsize;
+ sbp->f_iosize = tmpstat.f_iosize;
+ sbp->f_blocks = tmpstat.f_blocks;
+ sbp->f_bfree = tmpstat.f_bfree;
+ sbp->f_bavail = tmpstat.f_bavail;
+ sbp->f_files = tmpstat.f_files;
+ sbp->f_ffree = tmpstat.f_ffree;
+ if (sbp != &mp->mnt_stat) {
+ bcopy(&mp->mnt_stat.f_fsid, &sbp->f_fsid, sizeof(sbp->f_fsid));
+ bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
+ bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
+ }
+ return (0);
+}
+
+static int
+lomacfs_unmount(struct mount *mp, int mntflags, struct thread *td) {
+ struct vnode *crootvp = VFSTOLOMAC(mp)->lm_rootvp;
+ int error;
+ int flags = 0;
+
+ if (mntflags & MNT_FORCE)
+ flags |= FORCECLOSE;
+
+ if (VFSTOLOMAC(mp)->lm_flags & LM_TOOKROOT) {
+ mtx_lock(&crootvp->v_interlock);
+ crootvp->v_flag |= VROOT;
+ mtx_unlock(&crootvp->v_interlock);
+ }
+
+ error = vflush(mp, 1, flags); /* have an extra root ref */
+ if (error)
+ return (error);
+
+ free(VFSTOLOMAC(mp), M_LOMACFS);
+
+ /* bye, lomacfs. */
+ return (0);
+}
+
+static int
+lomacfs_root(struct mount *mp, struct vnode **vpp) {
+ int error;
+
+ if (VFSTOLOMAC(mp)->lm_rootvp == NULL) {
+ struct vnode *rootvp, *crootvp;
+
+ crootvp = mp->mnt_vnodecovered;
+ error = lomacfs_node_alloc(mp, NULL, NULL, crootvp, &rootvp);
+ if (error)
+ return (error);
+ /*
+ * Reference twice to match the rest of the lomacfs vnodes.
+ */
+ vref(crootvp);
+ vref(crootvp);
+ VFSTOLOMAC(mp)->lm_rootvp = rootvp;
+ /*
+ * This releases the lock on root, but it doesn't release
+ * the reference so that root won't "disappear" until
+ * unmount.
+ */
+ error = VOP_UNLOCK(rootvp, 0, curthread);
+ if (error)
+ return (error);
+ /*
+ * This is some strange magic here... I need to pretend
+ * that the mounted-on directory isn't a root vnode if I
+ * want things like __getcwd() to just fail and not crash.
+ */
+ mtx_lock(&crootvp->v_interlock);
+ if (crootvp->v_flag & VROOT && crootvp == rootvnode) {
+ crootvp->v_flag &= ~VROOT;
+ VFSTOLOMAC(mp)->lm_flags |= LM_TOOKROOT;
+ }
+ mtx_unlock(&crootvp->v_interlock);
+ }
+ *vpp = VFSTOLOMAC(mp)->lm_rootvp;
+ return (vget(*vpp, LK_EXCLUSIVE, curthread));
+}
+
+static struct vfsops lomacfs_vfsops = {
+ lomacfs_mount,
+ vfs_stdstart,
+ lomacfs_unmount,
+ lomacfs_root,
+ vfs_stdquotactl,
+ lomacfs_statfs,
+ vfs_stdsync,
+ vfs_stdvget,
+ vfs_stdfhtovp,
+ vfs_stdcheckexp,
+ vfs_stdvptofh,
+ vfs_stdinit,
+ vfs_stduninit,
+ vfs_stdextattrctl
+};
+VFS_SET(lomacfs_vfsops, lomacfs, VFCF_LOOPBACK);
+MODULE_VERSION(lomacfs, 1);
+MODULE_DEPEND(lomacfs, lomac_plm, 1, 1, 1);
diff --git a/sys/security/lomac/lomacfs_vnops.c b/sys/security/lomac/lomacfs_vnops.c
new file mode 100644
index 0000000..4a2e3c1
--- /dev/null
+++ b/sys/security/lomac/lomacfs_vnops.c
@@ -0,0 +1,1150 @@
+/*-
+ * Copyright (c) 2001 Networks Associates Technologies, Inc.
+ * All rights reserved.
+ *
+ * This software was developed for the FreeBSD Project 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.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * 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.
+ *
+ * $Id$
+ * $FreeBSD$
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/proc.h>
+#include <sys/mount.h>
+#include <sys/namei.h>
+#include <sys/sysctl.h>
+#include <sys/vnode.h>
+
+#include <vm/vm.h>
+#include <vm/vm_object.h>
+#include <vm/vnode_pager.h>
+
+#include <machine/limits.h>
+
+#include "lomacfs.h"
+#include "kernel_mediate.h"
+#include "kernel_monitor.h"
+
+#if defined(LOMAC_DEBUG_LOOKUPSTATS)
+static unsigned int lomacfs_successful_lookups, lomacfs_failed_lookups,
+ lomacfs_successful_cachedlookups, lomacfs_failed_cachedlookups,
+ lomacfs_node_alloc_clashes, lomacfs_node_alloc_failures;
+
+SYSCTL_NODE(_vfs, OID_AUTO, lomacfs, CTLFLAG_RW, 0, "LOMACFS filesystem");
+SYSCTL_NODE(_vfs_lomacfs, OID_AUTO, debug, CTLFLAG_RW, 0, "debug stats");
+SYSCTL_UINT(_vfs_lomacfs_debug, OID_AUTO, successful_lookups,
+ CTLFLAG_RW, &lomacfs_successful_lookups, 0, "");
+SYSCTL_UINT(_vfs_lomacfs_debug, OID_AUTO, failed_lookups,
+ CTLFLAG_RW, &lomacfs_failed_lookups, 0, "");
+SYSCTL_UINT(_vfs_lomacfs_debug, OID_AUTO, successful_cachedlookups,
+ CTLFLAG_RW, &lomacfs_successful_cachedlookups, 0, "");
+SYSCTL_UINT(_vfs_lomacfs_debug, OID_AUTO, failed_cachedlookups,
+ CTLFLAG_RW, &lomacfs_failed_cachedlookups, 0, "");
+SYSCTL_UINT(_vfs_lomacfs_debug, OID_AUTO, node_alloc_clashes,
+ CTLFLAG_RW, &lomacfs_node_alloc_clashes, 0, "");
+SYSCTL_UINT(_vfs_lomacfs_debug, OID_AUTO, node_alloc_failures,
+ CTLFLAG_RW, &lomacfs_node_alloc_failures, 0, "");
+#endif
+
+static int
+lomacfs_defaultop(
+ struct vop_generic_args /* {
+ struct vnodeop_desc *a_desc;
+ } */ *ap
+) {
+
+ printf("lomacfs: %s unsupported\n", ap->a_desc->vdesc_name);
+ return (EOPNOTSUPP);
+}
+
+static int
+lomacfs_inactive(
+ struct vop_inactive_args /* {
+ struct vnode *a_vp;
+ struct thread *a_td;
+ } */ *ap
+) {
+ struct vnode *vp = ap->a_vp;
+ struct vnode *lvp = VTOLVP(vp);
+ struct thread *td = ap->a_td;
+
+ KASSERT(lvp != NULL, ("inactive with NULL lowervp"));
+ VOP_UNLOCK(ap->a_vp, 0, td);
+ /*
+ * Temporarily drop our reference to the lower vnode, while keeping
+ * it held, to possibly call VOP_INACTIVE() on the lower layer.
+ */
+ vrele(lvp);
+#if defined(LOMAC_DEBUG_INACTIVE)
+ do {
+#if defined(LOMAC_DEBUG_INCNAME)
+ const char *name = VTOLOMAC(vp)->ln_name;
+#else
+ const char *name = "[unknown]";
+#endif
+ printf("lomacfs: inactive(%p \"%s\"), lvp usecount down to %u\n",
+ vp, name, lvp->v_usecount);
+ } while (0);
+#endif
+ /*
+ * Since the lower fs may actually remove the vnode on last
+ * release, destroy ourselves mostly here if that occurs.
+ *
+ * Additionally, devices should be totally freed
+ * on last close, not lazily.
+ */
+ if (lvp->v_usecount == 0 &&
+ (lvp->v_type != VREG && lvp->v_type != VDIR)) {
+ vdrop(lvp);
+ VTOLVP(vp) = NULL;
+ cache_purge(vp);
+ } else
+ vref(lvp);
+ return (0);
+}
+
+static int
+lomacfs_reclaim(
+ struct vop_reclaim_args /* {
+ struct vnode *a_vp;
+ struct thread *a_td;
+ } */ *ap
+) {
+ struct vnode *vp = ap->a_vp;
+ struct lomac_node *ln = VTOLOMAC(vp);
+ struct vnode *lvp = VTOLVP(vp);
+
+ if (lvp != NULL)
+ vrele(lvp);
+#if defined(LOMAC_DEBUG_RECLAIM)
+ if (lvp != NULL) {
+#if defined(LOMAC_DEBUG_INCNAME)
+ const char *name = ln->ln_name;
+#else
+ const char *name = "[unknown]";
+#endif
+ printf("lomacfs: reclaim(%p \"%s\"), lvp usecount down to %u\n",
+ vp, name, lvp->v_usecount);
+ }
+#endif
+ if (lvp != NULL)
+ vdrop(lvp);
+ vp->v_data = NULL;
+ vp->v_rdev = NULL;
+ free(ln, M_LOMACFS);
+
+ return (0);
+}
+
+static int
+lomacfs_print(
+ struct vop_print_args /* {
+ struct vnode *a_vp;
+ } */ *ap
+) {
+ struct vnode *vp = ap->a_vp;
+
+ printf ("\ttag VT_LOMACFS, vp=%p, lowervp=%p\n", vp,
+ VTOLVP(vp));
+ return (0);
+}
+
+static int
+lomacfs_lock(
+ struct vop_lock_args /* {
+ struct vnode *a_vp;
+ int a_flags;
+ struct thread *a_td;
+ } */ *ap
+) {
+ struct vnode *vp = ap->a_vp;
+ int flags = ap->a_flags;
+ struct thread *td = ap->a_td;
+ struct vnode *lvp;
+ int lflags = flags & ~(LK_INTERLOCK | LK_THISLAYER);
+ int error;
+
+ /*
+ * To prevent race conditions involving doing a lookup
+ * on "..", we have to lock the lower node, then lock our
+ * node. Most of the time it won't matter that we lock our
+ * node (as any locking would need the lower one locked
+ * first). But we can LK_DRAIN the upper lock as a step
+ * towards decomissioning it.
+ */
+ lvp = VTOLVP(vp);
+ if (lvp == NULL || flags & LK_THISLAYER)
+ return (lockmgr(&vp->v_lock, flags, &vp->v_interlock, td));
+ if (flags & LK_INTERLOCK) {
+ mtx_unlock(&vp->v_interlock);
+ flags &= ~LK_INTERLOCK;
+ }
+ if ((flags & LK_TYPE_MASK) == LK_DRAIN) {
+ error = vn_lock(lvp,
+ (lflags & ~LK_TYPE_MASK) | LK_EXCLUSIVE | LK_CANRECURSE,
+ td);
+ } else
+ error = vn_lock(lvp, lflags | LK_CANRECURSE, td);
+ if (error)
+ return (error);
+ error = lockmgr(&vp->v_lock, flags, &vp->v_interlock, td);
+ if (error)
+ VOP_UNLOCK(lvp, 0, td);
+ return (error);
+}
+
+/*
+ * We need to process our own vnode unlock and then clear the
+ * interlock flag as it applies only to our vnode, not the
+ * vnodes below us on the stack.
+ */
+static int
+lomacfs_unlock(
+ struct vop_unlock_args /* {
+ struct vnode *a_vp;
+ int a_flags;
+ struct thread *a_td;
+ } */ *ap
+) {
+ struct vnode *vp = ap->a_vp;
+ int flags = ap->a_flags;
+ int lflags = (ap->a_flags | LK_RELEASE) &
+ ~(LK_THISLAYER | LK_INTERLOCK);
+ struct thread *td = ap->a_td;
+ struct vnode *lvp = VTOLVP(vp);
+ int error;
+
+ error = lockmgr(&vp->v_lock, flags | LK_RELEASE, &vp->v_interlock, td);
+ if (lvp == NULL || flags & LK_THISLAYER || error)
+ return (error);
+ /*
+ * Hmm... in a vput(), this means we'll grab the lomacfs interlock,
+ * then the lower interlock. I don't think this matters, though,
+ * since both won't be held at the same time.
+ */
+ if (lvp != NULL)
+ error = VOP_UNLOCK(lvp, lflags, td);
+ return (error);
+}
+
+static int
+lomacfs_islocked(
+ struct vop_islocked_args /* {
+ struct vnode *a_vp;
+ struct thread *a_td;
+ } */ *ap
+) {
+
+ struct vnode *vp = ap->a_vp;
+ struct thread *td = ap->a_td;
+
+ return (lockstatus(&vp->v_lock, td));
+}
+
+static int
+lomacfs_lookup(
+ struct vop_lookup_args /* {
+ struct vnode *a_dvp;
+ struct vnode **a_vpp;
+ struct componentname *a_cnp;
+ } */ *ap
+) {
+ int error;
+
+ error = vfs_cache_lookup(ap);
+#if defined(LOMAC_DEBUG_LOOKUPSTATS)
+ if (error == 0)
+ lomacfs_successful_lookups++;
+ else
+ lomacfs_failed_lookups++;
+#endif
+#if defined(LOMAC_DEBUG_LOOKUP)
+ if (error == 0 && (*ap->a_vpp)->v_mount == dvp->v_mount) {
+ struct vnode *vp = *ap->a_vpp;
+#if defined(LOMAC_DEBUG_INCNAME)
+ const char *name = VTOLOMAC(vp)->ln_name;
+#else
+ const char *name = "[unknown]";
+#endif
+ printf("lomacfs: lookup(%p \"%s\"), lvp usecount up to %u\n",
+ vp, name, VTOLVP(vp)->v_usecount);
+ }
+#endif
+ return (error);
+}
+
+static int
+lomacfs_cachedlookup(
+ struct vop_lookup_args /* {
+ struct vnode *a_dvp;
+ struct vnode **a_vpp;
+ struct componentname *a_cnp;
+ } */ *ap
+) {
+ struct vnode *dvp = ap->a_dvp;
+ struct componentname *cnp = ap->a_cnp;
+ struct vnode *ldvp = VTOLVP(dvp);
+ struct vnode *lvp;
+ int makeentry;
+ int error;
+
+ if (cnp->cn_flags & ISLASTCN && cnp->cn_nameiop != LOOKUP &&
+ cnp->cn_nameiop != CREATE) {
+ lomac_object_t lobj = { LO_TYPE_LVNODE, { dvp } };
+ const char *op;
+
+ if (cnp->cn_nameiop == DELETE)
+ op = "delete";
+ else
+ op = "rename";
+
+ if (!mediate_subject_object(op, curthread->td_proc, &lobj))
+ return (EPERM);
+ }
+ makeentry = cnp->cn_flags & MAKEENTRY;
+ cnp->cn_flags &= ~makeentry;
+ error = VOP_LOOKUP(ldvp, &lvp, cnp);
+ cnp->cn_flags |= makeentry;
+ if ((error == 0 || error == EJUSTRETURN) &&
+ cnp->cn_flags != (cnp->cn_flags | LOCKPARENT | ISLASTCN))
+ (void)VOP_UNLOCK(dvp, LK_THISLAYER, curthread);
+ if (error == 0 && lvp->v_type != VSOCK) {
+ struct mount *mp;
+
+ /*
+ * Check to see if the vnode has been mounted on;
+ * if so find the root of the mounted file system.
+ */
+ if (lvp->v_type == VDIR && (mp = lvp->v_mountedhere) &&
+ (cnp->cn_flags & NOCROSSMOUNT) == 0) {
+ struct vnode *tdp;
+
+ if (vfs_busy(mp, 0, 0, curthread))
+ goto forget_it;
+ VOP_UNLOCK(lvp, 0, curthread);
+ error = VFS_ROOT(mp, &tdp);
+ vfs_unbusy(mp, curthread);
+ if (error) {
+ vrele(lvp);
+ return (error);
+ }
+ vrele(lvp);
+ lvp = tdp;
+ }
+forget_it:
+ /*
+ * For a create or for devices (dynamic things, aren't they),
+ * don't enter the vnode into the cache.
+ */
+ if (cnp->cn_nameiop == CREATE || lvp->v_type == VCHR)
+ cnp->cn_flags &= ~makeentry;
+ /*
+ * The top half of dvp is locked, but ldvp is unlocked.
+ * Additionally, lvp is locked already, and
+ * lomacfs_node_alloc() always returns it locked.
+ */
+ error = lomacfs_node_alloc(dvp->v_mount, cnp,
+ dvp, lvp, ap->a_vpp);
+ if (cnp->cn_nameiop == CREATE)
+ cnp->cn_flags |= makeentry;
+#if defined(LOMAC_DEBUG_LOOKUPSTATS)
+ if (error) {
+ if (error != EEXIST) {
+ lomacfs_node_alloc_failures++;
+ } else {
+ lomacfs_node_alloc_clashes++;
+ error = 0;
+ }
+ }
+#else
+ if (error == EEXIST)
+ error = 0;
+#endif
+ } else if (error == 0) {
+ /*
+ * For sockets, just return the "real" thing
+ * after entering it into the cache.
+ */
+ *ap->a_vpp = lvp;
+ if (cnp->cn_nameiop != CREATE && cnp->cn_flags & MAKEENTRY)
+ cache_enter(dvp, lvp, cnp);
+ }
+
+#if defined(LOMAC_DEBUG_LOOKUPSTATS)
+ if (error == 0)
+ lomacfs_successful_cachedlookups++;
+ else
+ lomacfs_failed_cachedlookups++;
+#endif
+ return (error);
+}
+
+static int
+lomacfs_getattr(
+ struct vop_getattr_args /* {
+ struct vnode *a_vp;
+ struct vattr *a_vap;
+ struct ucred *a_cred;
+ struct thread *a_td;
+ */ *ap
+) {
+ struct vnode *vp = ap->a_vp;
+ struct vattr *vap = ap->a_vap;
+ int error;
+
+ error = VOP_GETATTR(VTOLVP(vp), vap, ap->a_cred, ap->a_td);
+ if (error == 0 && vap->va_fsid == VNOVAL)
+ vap->va_fsid = VTOLVP(vp)->v_mount->mnt_stat.f_fsid.val[0];
+ return (error);
+}
+
+static int
+lomacfs_setattr(
+ struct vop_getattr_args /* {
+ struct vnode *a_vp;
+ struct vattr *a_vap;
+ struct ucred *a_cred;
+ struct thread *a_td;
+ */ *ap
+) {
+ lomac_object_t lobj = { LO_TYPE_LVNODE, { ap->a_vp } };
+ int error;
+
+ if (mediate_subject_object(ap->a_desc->vdesc_name, curthread->td_proc,
+ &lobj))
+ error = VOP_SETATTR(VTOLVP(ap->a_vp), ap->a_vap, ap->a_cred,
+ ap->a_td);
+ else
+ error = EPERM;
+ return (error);
+}
+
+static int
+lomacfs_readdir(
+ struct vop_readdir_args /* {
+ struct vnode *a_vp;
+ struct uio *a_uio;
+ struct ucred *a_cred;
+ int *a_eofflag;
+ int *a_ncookies;
+ u_long **a_cookies;
+ } */ *ap
+) {
+
+ return (VOP_READDIR(VTOLVP(ap->a_vp), ap->a_uio, ap->a_cred,
+ ap->a_eofflag, ap->a_ncookies, ap->a_cookies));
+}
+
+static int
+lomacfs_open(
+ struct vop_open_args /* {
+ struct vnode *a_vp;
+ int a_mode;
+ struct ucred *a_cred;
+ struct thread *a_td;
+ } */ *ap
+) {
+ lomac_object_t lobj;
+ int error;
+
+ lobj.lo_type = LO_TYPE_LVNODE;
+ lobj.lo_object.vnode = ap->a_vp;
+ if (!mediate_subject_object_open(ap->a_td->td_proc, &lobj))
+ error = EPERM;
+ else
+ error = VOP_OPEN(VTOLVP(ap->a_vp), ap->a_mode, ap->a_cred,
+ ap->a_td);
+ return (error);
+}
+
+static int
+lomacfs_close(
+ struct vop_close_args /* {
+ struct vnode *a_vp;
+ int a_fflag;
+ struct ucred *a_cred;
+ struct thread *a_td;
+ } */ *ap
+) {
+ struct vnode *vp = ap->a_vp;
+ struct vnode *lvp = VTOLVP(vp);
+ int error;
+
+ /*
+ * XXX
+ * Try to cope with the horrible semantics introduced here...
+ */
+ vref(lvp);
+ error = VOP_CLOSE(lvp, ap->a_fflag, ap->a_cred, ap->a_td);
+ if (error == EAGAIN)
+ error = 0;
+ else
+ vrele(lvp);
+ return (error);
+}
+
+static int
+lomacfs_access(
+ struct vop_access_args /* {
+ struct vnode *a_vp;
+ int a_mode;
+ struct ucred *a_cred;
+ struct thread *a_td;
+ } */ *ap
+) {
+
+ return (VOP_ACCESS(VTOLVP(ap->a_vp), ap->a_mode, ap->a_cred, ap->a_td));
+}
+
+static int
+lomacfs_readlink(
+ struct vop_readlink_args /* {
+ struct vnode *a_vp;
+ struct uio *a_uio;
+ struct ucred *a_cred;
+ } */ *ap
+) {
+ struct vnode *lvp = VTOLVP(ap->a_vp);
+
+ if (lvp == NULL)
+ return (EPERM);
+ return (VOP_READLINK(lvp, ap->a_uio, ap->a_cred));
+}
+
+static int
+lomacfs_lease(
+ struct vop_lease_args /* {
+ struct vnode *a_vp;
+ struct thread *a_td;
+ struct ucred *a_cred;
+ int a_flag;
+ } */ *ap
+) {
+ struct vnode *lvp = VTOLVP(ap->a_vp);
+
+ return (VOP_LEASE(lvp, ap->a_td, ap->a_cred, ap->a_flag));
+}
+
+static int
+lomacfs_read(
+ struct vop_read_args /* {
+ struct vnode *a_vp;
+ struct uio *a_uio;
+ int a_ioflag;
+ struct ucred *a_cred;
+ } */ *ap
+) {
+ struct vnode *lvp = VTOLVP(ap->a_vp);
+ lomac_object_t lobj = { LO_TYPE_LVNODE, { ap->a_vp } };
+ int error;
+
+ error = monitor_read_object(curthread->td_proc, &lobj);
+ if (error == 0)
+ error = VOP_READ(lvp, ap->a_uio, ap->a_ioflag, ap->a_cred);
+ return (error);
+}
+
+static int
+lomacfs_write(
+ struct vop_write_args /* {
+ struct vnode *a_vp;
+ struct uio *a_uio;
+ int a_ioflag;
+ struct ucred *a_cred;
+ } */ *ap
+) {
+ struct vnode *lvp = VTOLVP(ap->a_vp);
+ lomac_object_t lobj = { LO_TYPE_LVNODE, { ap->a_vp } };
+ int error;
+
+ if (mediate_subject_object(ap->a_desc->vdesc_name, curthread->td_proc,
+ &lobj))
+ error = VOP_WRITE(lvp, ap->a_uio, ap->a_ioflag, ap->a_cred);
+ else
+ error = EPERM;
+ return (error);
+}
+
+static int
+lomacfs_ioctl(
+ struct vop_ioctl_args /* {
+ struct vnode *a_vp;
+ u_long a_command;
+ caddr_t a_data;
+ int a_fflag;
+ struct ucred *a_cred;
+ struct thread *a_td;
+ } */ *ap
+) {
+ struct vnode *lvp = VTOLVP(ap->a_vp);
+
+ return (VOP_IOCTL(lvp, ap->a_command, ap->a_data, ap->a_fflag,
+ ap->a_cred, ap->a_td));
+}
+
+static int
+lomacfs_muxcreate(
+ struct vop_create_args /* {
+ struct vnode *a_dvp;
+ struct vnode **a_vpp;
+ struct componentname *a_cnp;
+ struct vattr *a_vap;
+ } */ *ap
+) {
+ struct vnode *dvp = ap->a_dvp;
+ struct vnode *ldvp = VTOLVP(dvp);
+ struct componentname *cnp = ap->a_cnp;
+ struct vattr *vap = ap->a_vap;
+ int makeentry = cnp->cn_flags & MAKEENTRY;
+ lomac_object_t lobj = { LO_TYPE_LVNODE, { dvp } };
+ struct thread *td = curthread;
+ int error;
+
+ if (!mediate_subject_object(ap->a_desc->vdesc_name, td->td_proc,
+ &lobj) || (vap->va_type == VCHR &&
+ !mediate_subject_at_level("mknod", curthread->td_proc,
+ LOMAC_HIGHEST_LEVEL)))
+ return (EPERM);
+ ap->a_dvp = ldvp;
+ cnp->cn_flags &= ~makeentry;
+ error = VCALL(ldvp, ap->a_desc->vdesc_offset, ap);
+ if (error == 0) {
+ struct vnode *vp;
+ int issock;
+
+ issock = vap->va_type == VSOCK;
+ vp = *ap->a_vpp;
+ *ap->a_vpp = NULL;
+ if (!issock)
+ cnp->cn_flags |= makeentry;
+ error = lomacfs_node_alloc(dvp->v_mount, cnp, dvp, vp,
+ ap->a_vpp);
+ if (error)
+ vput(vp);
+ else if (issock) {
+ /*
+ * I should really find a nicer way to do this.
+ */
+ vref(vp);
+ vput(*ap->a_vpp);
+ *ap->a_vpp = vp;
+ (void)VOP_LOCK(vp, LK_EXCLUSIVE | LK_RETRY, td);
+ }
+ }
+ return (error);
+}
+
+static int
+lomacfs_muxremove(
+ struct vop_remove_args /* {
+ struct vnode *a_dvp;
+ struct vnode *a_vp;
+ struct componentname *a_cnp;
+ } */ *ap
+) {
+ struct vnode *dvp = ap->a_dvp;
+ struct vnode *vp = ap->a_vp;
+ int error;
+
+ ap->a_dvp = VTOLVP(dvp);
+ if (VISLOMAC(vp))
+ ap->a_vp = VTOLVP(vp);
+ error = VCALL(ap->a_dvp, ap->a_desc->vdesc_offset, ap);
+ if (error == 0)
+ cache_purge(vp);
+ return (error);
+}
+
+static int
+lomacfs_fsync(
+ struct vop_fsync_args /* {
+ struct vnode *a_vp;
+ struct ucred *a_cred;
+ int a_waitfor;
+ struct thread *a_td;
+ } */ *ap
+) {
+
+ return (VOP_FSYNC(VTOLVP(ap->a_vp), ap->a_cred, ap->a_waitfor,
+ ap->a_td));
+}
+
+static int
+lomacfs_advlock(
+ struct vop_advlock_args /* {
+ struct vnode *a_vp;
+ caddr_t a_id;
+ int a_op;
+ struct flock *a_fl;
+ int a_flags;
+ } */ *ap
+) {
+
+ return (VOP_ADVLOCK(VTOLVP(ap->a_vp), ap->a_id, ap->a_op, ap->a_fl,
+ ap->a_flags));
+}
+
+static int
+lomacfs_whiteout(
+ struct vop_whiteout_args /* {
+ struct vnode *a_dvp;
+ struct componentname *a_cnp;
+ int a_flags;
+ } */ *ap
+) {
+
+ return (VOP_WHITEOUT(VTOLVP(ap->a_dvp), ap->a_cnp, ap->a_flags));
+}
+
+static int
+lomacfs_poll(
+ struct vop_poll_args /* {
+ struct vnode *a_vp;
+ int a_events;
+ struct ucred *a_cred;
+ struct thread *a_td;
+ } */ *ap
+) {
+
+ return (VOP_POLL(VTOLVP(ap->a_vp), ap->a_events, ap->a_cred, ap->a_td));
+}
+
+static int
+lomacfs_revoke(
+ struct vop_revoke_args /* {
+ struct vnode *a_vp;
+ int a_flags;
+ } */ *ap
+) {
+
+ return (VOP_REVOKE(VTOLVP(ap->a_vp), ap->a_flags));
+}
+
+static int
+lomacfs_link(
+ struct vop_link_args /* {
+ struct vnode *a_tdvp;
+ struct vnode *a_vp;
+ struct componentname *a_cnp;
+ } */ *ap
+) {
+ struct vnode *tdvp = ap->a_tdvp;
+ struct vnode *vp = ap->a_vp;
+ struct vnode *lvp = VISLOMAC(vp) ? VTOLVP(vp) : vp;
+ struct componentname *cnp = ap->a_cnp;
+ int error;
+
+ error = VOP_LINK(VTOLVP(tdvp), lvp, cnp);
+ if (error == 0 && vp->v_type == VSOCK) {
+ cache_enter(tdvp, vp, cnp);
+#if defined(LOMAC_DEBUG_LINK)
+ do {
+ struct vnode *nvp;
+ int nerror;
+
+ nerror = cache_lookup(tdvp, &nvp, cnp);
+ printf("lomacfs: link(%p), cache_lookup() = %d (%p)\n",
+ vp, nerror, nvp);
+ } while (0);
+#endif
+ }
+ return (error);
+}
+
+static int
+lomacfs_rename(
+ struct vop_rename_args /* {
+ struct vnode *a_fdvp;
+ struct vnode *a_fvp;
+ struct componentname *a_fcnp;
+ struct vnode *a_tdvp;
+ struct vnode *a_tvp;
+ struct componentname *a_tcnp;
+ } */ *ap
+) {
+ struct vnode *fdvp = ap->a_fdvp;
+ struct vnode *fvp = ap->a_fvp;
+ struct componentname *fcnp = ap->a_fcnp;
+ struct vnode *tdvp = ap->a_tdvp;
+ struct vnode *tvp = ap->a_tvp;
+ struct componentname *tcnp = ap->a_tcnp;
+ int fvp_is_lomac = VISLOMAC(fvp);
+ int error;
+
+ vref(VTOLVP(fdvp));
+ /*
+ * Handle the case when LOMAC returns a real vnode for
+ * VSOCK, rather than the LOMAC covering vnode.
+ */
+ if (fvp_is_lomac)
+ vref(VTOLVP(fvp));
+ vref(VTOLVP(tdvp));
+ if (tvp != NULL)
+ vref(VTOLVP(tvp));
+ error = VOP_RENAME(VTOLVP(fdvp), fvp_is_lomac ? VTOLVP(fvp) : fvp, fcnp,
+ VTOLVP(tdvp), tvp != NULL ? VTOLVP(tvp) : NULL, tcnp);
+ if (fvp->v_type == VDIR) {
+ if (tvp != NULL && tvp->v_type == VDIR)
+ cache_purge(tdvp);
+ cache_purge(fdvp);
+ }
+ cache_purge(fvp);
+ if (tvp != NULL)
+ cache_purge(tvp);
+ (void)VOP_UNLOCK(tdvp, LK_THISLAYER, curthread);
+ vrele(fdvp);
+ if (fvp_is_lomac)
+ vrele(fvp);
+ vrele(tdvp);
+ if (tvp != NULL) {
+ (void)VOP_UNLOCK(tvp, LK_THISLAYER, curthread);
+ vrele(tvp);
+ } else if (tcnp->cn_nameiop == RENAME /* NOCACHE unsets MAKEENTRY */
+ && fvp->v_type == VSOCK)
+ cache_enter(tdvp, fvp, tcnp);
+ return (error);
+}
+
+static int
+lomacfs_strategy(
+ struct vop_strategy_args /* {
+ struct vnode *a_vp;
+ struct buf *a_bp;
+ } */ *ap
+) {
+
+ return (VOP_STRATEGY(VTOLVP(ap->a_vp), ap->a_bp));
+}
+
+/*
+ * Let an underlying filesystem do the work of creating the "actual"
+ * vm_object_t, and we will reference it.
+ */
+static int
+lomacfs_createvobject(
+ struct vop_createvobject_args /* {
+ struct vnode *vp;
+ struct ucred *cred;
+ struct proc *p;
+ } */ *ap
+) {
+ struct vnode *vp = ap->a_vp;
+ struct vnode *lowervp = VTOLOMAC(vp) != NULL ? VTOLVP(vp) : NULL;
+ int error;
+
+ if (vp->v_type == VNON || lowervp == NULL)
+ return (EINVAL);
+ error = VOP_CREATEVOBJECT(lowervp, ap->a_cred, ap->a_td);
+ if (error)
+ return (error);
+ vp->v_flag |= VOBJBUF;
+ return (error);
+}
+
+/*
+ * We need to destroy the lower vnode object only if we created it.
+ * XXX - I am very unsure about all of this.
+ */
+static int
+lomacfs_destroyvobject(
+ struct vop_destroyvobject_args /* {
+ struct vnode *vp;
+ } */ *ap
+) {
+ struct vnode *vp = ap->a_vp;
+
+ vp->v_flag &= ~VOBJBUF;
+ return (0);
+}
+
+static int
+lomacfs_bmap(
+ struct vop_bmap_args /* {
+ struct vnode *a_vp;
+ daddr_t a_bn;
+ struct vnode **a_vpp;
+ daddr_t *a_bnp;
+ int *a_runp;
+ int *a_runb;
+ } */ *ap
+) {
+
+ return (VOP_BMAP(VTOLVP(ap->a_vp), ap->a_bn, ap->a_vpp, ap->a_bnp,
+ ap->a_runp, ap->a_runb));
+}
+
+static int
+lomacfs_getpages(
+ struct vop_getpages_args /* {
+ struct vnode *a_vp;
+ vm_page_t *a_m;
+ int a_count;
+ int a_reqpage;
+ vm_ooffset_t a_offset;
+ } */ *ap
+) {
+
+ return (VOP_GETPAGES(VTOLVP(ap->a_vp), ap->a_m, ap->a_count,
+ ap->a_reqpage, ap->a_offset));
+}
+
+static int
+lomacfs_putpages(
+ struct vop_putpages_args /* {
+ struct vnode *a_vp;
+ vm_page_t *a_m;
+ int a_count;
+ int a_sync;
+ int *a_rtvals;
+ vm_ooffset_t a_offset;
+ } */ *ap
+) {
+
+ return (VOP_PUTPAGES(VTOLVP(ap->a_vp), ap->a_m, ap->a_count,
+ ap->a_sync, ap->a_rtvals, ap->a_offset));
+}
+
+static int
+lomacfs_getvobject(
+ struct vop_getvobject_args /* {
+ struct vnode *a_vp;
+ struct vm_object **a_objpp;
+ } */ *ap
+) {
+ struct vnode *lvp = VTOLVP(ap->a_vp);
+
+ if (lvp == NULL)
+ return EINVAL;
+ return (VOP_GETVOBJECT(lvp, ap->a_objpp));
+}
+
+static int
+lomacfs_kqfilter(
+ struct vop_kqfilter_args /* {
+ struct vnode *a_vp;
+ struct knote *a_kn;
+ } */ *ap
+) {
+
+ return (VOP_KQFILTER(VTOLVP(ap->a_vp), ap->a_kn));
+}
+
+static int
+lomacfs_pathconf(
+ struct vop_pathconf_args /* {
+ struct vnode *a_vp;
+ int a_name;
+ register_t *a_retval;
+ } */ *ap
+) {
+
+ return (VOP_PATHCONF(VTOLVP(ap->a_vp), ap->a_name, ap->a_retval));
+}
+
+static int
+lomacfs_reallocblks(
+ struct vop_reallocblks_args /* {
+ struct vnode *a_vp;
+ struct cluster_save *a_buflist;
+ } */ *ap
+) {
+
+ return (VOP_REALLOCBLKS(VTOLVP(ap->a_vp), ap->a_buflist));
+}
+
+static int
+lomacfs_freeblks(
+ struct vop_freeblks_args /* {
+ struct vnode *a_vp;
+ daddr_t a_addr;
+ daddr_t a_length;
+ } */ *ap
+) {
+
+ return (VOP_FREEBLKS(VTOLVP(ap->a_vp), ap->a_addr, ap->a_length));
+}
+
+static int
+lomacfs_getacl(
+ struct vop_getacl_args /* {
+ struct vnode *a_vp;
+ acl_type_t a_type;
+ struct acl *a_aclp;
+ struct ucred *a_cred;
+ struct thread *a_td;
+ } */ *ap
+) {
+
+ return (VOP_GETACL(VTOLVP(ap->a_vp), ap->a_type, ap->a_aclp, ap->a_cred,
+ ap->a_td));
+}
+
+static int
+lomacfs_setacl(
+ struct vop_setacl_args /* {
+ struct vnode *a_vp;
+ acl_type_t a_type;
+ struct acl *a_aclp;
+ struct ucred *a_cred;
+ struct thread *a_td;
+ } */ *ap
+) {
+ lomac_object_t lobj;
+
+ lobj.lo_type = LO_TYPE_LVNODE;
+ lobj.lo_object.vnode = ap->a_vp;
+ if (!mediate_subject_object("setacl", ap->a_td->td_proc, &lobj))
+ return (EPERM);
+ else
+ return (VOP_SETACL(VTOLVP(ap->a_vp), ap->a_type, ap->a_aclp,
+ ap->a_cred, ap->a_td));
+}
+
+static int
+lomacfs_aclcheck(
+ struct vop_aclcheck_args /* {
+ struct vnode *a_vp;
+ acl_type_t a_type;
+ struct acl *a_aclp;
+ struct ucred *a_cred;
+ struct thread *a_td;
+ } */ *ap
+) {
+
+ return (VOP_ACLCHECK(VTOLVP(ap->a_vp), ap->a_type, ap->a_aclp,
+ ap->a_cred, ap->a_td));
+}
+
+static int
+lomacfs_getextattr(
+ struct vop_getextattr_args /* {
+ struct vnode *a_vp;
+ int a_attrnamespace;
+ const char *a_name;
+ struct uio *a_uio;
+ struct ucred *a_cred;
+ struct thread *a_td;
+ } */ *ap
+) {
+ lomac_object_t lobj;
+
+ lobj.lo_type = LO_TYPE_LVNODE;
+ lobj.lo_object.vnode = ap->a_vp;
+ if (monitor_read_object(ap->a_td->td_proc, &lobj))
+ return (EPERM);
+ else
+ return (VOP_GETEXTATTR(VTOLVP(ap->a_vp), ap->a_attrnamespace,
+ ap->a_name, ap->a_uio, ap->a_cred, ap->a_td));
+}
+
+static int
+lomacfs_setextattr(
+ struct vop_setextattr_args /* {
+ struct vnode *a_vp;
+ int a_attrnamespace;
+ const char *a_name;
+ struct uio *a_uio;
+ struct ucred *a_cred;
+ struct thread *a_td;
+ } */ *ap
+) {
+ lomac_object_t lobj;
+
+ lobj.lo_type = LO_TYPE_LVNODE;
+ lobj.lo_object.vnode = ap->a_vp;
+ if (!mediate_subject_object("setextattr", ap->a_td->td_proc, &lobj))
+ return (EPERM);
+ else
+ return (VOP_SETEXTATTR(VTOLVP(ap->a_vp), ap->a_attrnamespace,
+ ap->a_name, ap->a_uio, ap->a_cred, ap->a_td));
+}
+
+vop_t **lomacfs_vnodeop_p;
+static struct vnodeopv_entry_desc lomacfs_vnodeop_entries[] = {
+ { &vop_default_desc, (vop_t *)lomacfs_defaultop },
+ { &vop_inactive_desc, (vop_t *)lomacfs_inactive },
+ { &vop_reclaim_desc, (vop_t *)lomacfs_reclaim },
+ { &vop_print_desc, (vop_t *)lomacfs_print },
+ { &vop_lock_desc, (vop_t *)lomacfs_lock },
+ { &vop_unlock_desc, (vop_t *)lomacfs_unlock },
+ { &vop_islocked_desc, (vop_t *)lomacfs_islocked },
+ { &vop_lookup_desc, (vop_t *)lomacfs_lookup },
+ { &vop_setattr_desc, (vop_t *)lomacfs_setattr },
+ { &vop_getattr_desc, (vop_t *)lomacfs_getattr },
+ { &vop_readdir_desc, (vop_t *)lomacfs_readdir },
+ { &vop_open_desc, (vop_t *)lomacfs_open },
+ { &vop_close_desc, (vop_t *)lomacfs_close },
+ { &vop_access_desc, (vop_t *)lomacfs_access },
+ { &vop_readlink_desc, (vop_t *)lomacfs_readlink },
+ { &vop_lease_desc, (vop_t *)lomacfs_lease },
+ { &vop_read_desc, (vop_t *)lomacfs_read },
+ { &vop_write_desc, (vop_t *)lomacfs_write },
+ { &vop_ioctl_desc, (vop_t *)lomacfs_ioctl },
+ { &vop_create_desc, (vop_t *)lomacfs_muxcreate },
+ { &vop_mkdir_desc, (vop_t *)lomacfs_muxcreate },
+ { &vop_mknod_desc, (vop_t *)lomacfs_muxcreate },
+ { &vop_symlink_desc, (vop_t *)lomacfs_muxcreate },
+ { &vop_remove_desc, (vop_t *)lomacfs_muxremove },
+ { &vop_rmdir_desc, (vop_t *)lomacfs_muxremove },
+ { &vop_fsync_desc, (vop_t *)lomacfs_fsync },
+ { &vop_advlock_desc, (vop_t *)lomacfs_advlock },
+ { &vop_whiteout_desc, (vop_t *)lomacfs_whiteout },
+ { &vop_poll_desc, (vop_t *)lomacfs_poll },
+ { &vop_link_desc, (vop_t *)lomacfs_link },
+ { &vop_rename_desc, (vop_t *)lomacfs_rename },
+ { &vop_revoke_desc, (vop_t *)lomacfs_revoke },
+ { &vop_cachedlookup_desc, (vop_t *)lomacfs_cachedlookup },
+ { &vop_lookup_desc, (vop_t *)lomacfs_lookup },
+ { &vop_bmap_desc, (vop_t *)lomacfs_bmap },
+ { &vop_getpages_desc, (vop_t *)lomacfs_getpages },
+ { &vop_putpages_desc, (vop_t *)lomacfs_putpages },
+ { &vop_strategy_desc, (vop_t *)lomacfs_strategy },
+ { &vop_createvobject_desc, (vop_t *)lomacfs_createvobject },
+ { &vop_destroyvobject_desc, (vop_t *)lomacfs_destroyvobject },
+ { &vop_getvobject_desc, (vop_t *)lomacfs_getvobject },
+ { &vop_getwritemount_desc, (vop_t *)vop_stdgetwritemount },
+ { &vop_kqfilter_desc, (vop_t *)lomacfs_kqfilter },
+ { &vop_pathconf_desc, (vop_t *)lomacfs_pathconf },
+ { &vop_reallocblks_desc, (vop_t *)lomacfs_reallocblks },
+ { &vop_freeblks_desc, (vop_t *)lomacfs_freeblks },
+ { &vop_getacl_desc, (vop_t *)lomacfs_getacl },
+ { &vop_setacl_desc, (vop_t *)lomacfs_setacl },
+ { &vop_aclcheck_desc, (vop_t *)lomacfs_aclcheck },
+ { &vop_getextattr_desc, (vop_t *)lomacfs_getextattr },
+ { &vop_setextattr_desc, (vop_t *)lomacfs_setextattr },
+ { NULL, NULL }
+};
+static struct vnodeopv_desc lomacfs_vnodeopv_opv_desc =
+ { &lomacfs_vnodeop_p, lomacfs_vnodeop_entries };
+VNODEOP_SET(lomacfs_vnodeopv_opv_desc);
diff --git a/sys/security/lomac/lomacio.h b/sys/security/lomac/lomacio.h
new file mode 100644
index 0000000..33328e9
--- /dev/null
+++ b/sys/security/lomac/lomacio.h
@@ -0,0 +1,59 @@
+/*-
+ * Copyright (c) 2001 Networks Associates Technologies, Inc.
+ * All rights reserved.
+ *
+ * This software was developed for the FreeBSD Project 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.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * 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.
+ *
+ * $Id$
+ * $FreeBSD$
+ */
+
+#ifndef LOMACIO_H
+#define LOMACIO_H
+
+#include <sys/ioccom.h>
+#include <sys/param.h>
+
+struct lomac_fioctl {
+ char path[MAXPATHLEN];
+ int level; /* LOMAC security level */
+};
+
+struct lomac_fioctl2 {
+ char path[MAXPATHLEN];
+ int level; /* LOMAC security level */
+ int flags;
+};
+
+#define LIOGETPLEVEL _IOWR('L', 0, int) /* get process level */
+#define LIOGETFLEVEL _IOWR('L', 1, struct lomac_fioctl) /* get file level */
+#define LIOGETFLATTR _IOWR('L', 3, struct lomac_fioctl2) /* get file level */
+#define LIOPMAKELOWLEVEL _IO('L', 2) /* lower proc's level */
+#endif /* LOMACIO_H */
diff --git a/sys/security/lomac/policy_plm.h b/sys/security/lomac/policy_plm.h
new file mode 100644
index 0000000..533d4c3
--- /dev/null
+++ b/sys/security/lomac/policy_plm.h
@@ -0,0 +1,119 @@
+/*-
+ * Copyright (c) 2001 Networks Associates Technologies, Inc.
+ * All rights reserved.
+ *
+ * This software was developed for the FreeBSD Project 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.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * 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.
+ *
+ * $Id$
+ * $FreeBSD$
+ */
+
+#ifndef LOMAC_PLM_H
+#define LOMAC_PLM_H
+
+enum plm_level {
+ LOW,
+ SUBJ,
+ HIGH
+};
+enum plm_flags {
+ PLM_NOFLAGS, /* rule applies to this node and its children */
+ PLM_CHILDOF /* rule applies to node's children, not the node */
+};
+#define LOWWRITE LN_ATTR_LOWWRITE
+#define LOWNOOPEN LN_ATTR_LOWNOOPEN
+#define NONETDEMOTE LN_ATTR_NONETDEMOTE
+#define NODEMOTE LN_ATTR_NODEMOTE
+
+static u_int plm_levelflags_to_node_flags[3][2] = {
+ { LN_LOWEST_LEVEL, LN_INHERIT_LOW },
+ { LN_SUBJ_LEVEL, LN_INHERIT_SUBJ },
+ { LN_HIGHEST_LEVEL, LN_INHERIT_HIGH }
+};
+
+typedef struct plm_rule {
+ enum plm_level level; /* LOMAC level */
+ enum plm_flags flags; /* flags for PLM evaluation */
+ unsigned int attr; /* LN_ATTR_MASK of flags */
+ const char *path; /* absolute path for this PLM rule */
+} plm_rule_t;
+
+/* The `plm' array maps levels onto all of the files in the filesystem */
+static plm_rule_t plm[] = {
+ { HIGH, PLM_NOFLAGS, 0, "/" }, /* everything initially inherits high level */
+ { HIGH, PLM_CHILDOF, 0, "/" },
+ { HIGH, PLM_NOFLAGS, NONETDEMOTE, "/sbin/dhclient" },
+ { HIGH, PLM_CHILDOF, 0, "/var" },
+ { HIGH, PLM_CHILDOF, LOWWRITE, "/dev" },
+ { HIGH, PLM_NOFLAGS, LOWNOOPEN, "/dev/mdctl" },
+ { HIGH, PLM_NOFLAGS, LOWNOOPEN, "/dev/pci" },
+ { HIGH, PLM_NOFLAGS, LOWNOOPEN, "/dev/kmem" },
+ { HIGH, PLM_NOFLAGS, LOWNOOPEN, "/dev/mem" },
+ { HIGH, PLM_NOFLAGS, LOWNOOPEN, "/dev/io" },
+ { HIGH, PLM_CHILDOF, 0, "/etc" },
+ { HIGH, PLM_NOFLAGS, LOWWRITE, "/tmp" },
+ { SUBJ, PLM_CHILDOF, 0, "/tmp" },
+ { HIGH, PLM_NOFLAGS, 0, "/tmp/.X11-unix" },
+ { HIGH, PLM_CHILDOF, LOWWRITE, "/tmp/.X11-unix" },
+ { SUBJ, PLM_CHILDOF, 0, "/proc" },
+ { LOW, PLM_CHILDOF, 0, "/mnt" }, /* all nfs mounts are low */
+ { LOW, PLM_CHILDOF, 0, "/home" },
+ { HIGH, PLM_NOFLAGS, NONETDEMOTE, "/usr/bin/env-nonetdemote" },
+ { HIGH, PLM_NOFLAGS, NODEMOTE, "/usr/bin/env-nodemote" },
+ { LOW, PLM_CHILDOF, 0, "/usr/home" },
+ { LOW, PLM_CHILDOF, 0, "/var/lib" },
+ { HIGH, PLM_NOFLAGS, LOWWRITE, "/var/tmp" },
+ { SUBJ, PLM_CHILDOF, 0, "/var/tmp" },
+ { LOW, PLM_NOFLAGS, 0, "/var/tmp/vi.recover" },
+ { SUBJ, PLM_CHILDOF, 0, "/var/tmp/vi.recover" },
+ { HIGH, PLM_NOFLAGS, LOWWRITE, "/usr/tmp" },
+ { SUBJ, PLM_CHILDOF, 0, "/usr/tmp" },
+ { HIGH, PLM_NOFLAGS, 0, "/usr/tmp/.X11-unix" },
+ { HIGH, PLM_CHILDOF, LOWWRITE, "/usr/tmp/.X11-unix" },
+ { LOW, PLM_NOFLAGS, 0, "/var/mail" },
+ { LOW, PLM_CHILDOF, 0, "/var/mail" },
+ { LOW, PLM_NOFLAGS, 0, "/var/spool/mqueue" },
+ { LOW, PLM_CHILDOF, 0, "/var/spool/mqueue" },
+ { LOW, PLM_NOFLAGS, 0, "/dev/log" },
+ { HIGH, PLM_NOFLAGS, 0, "/home/ftp" },
+ { HIGH, PLM_NOFLAGS, 0, "/usr/home/ftp" },
+ { HIGH, PLM_NOFLAGS, 0, "/mnt/cdrom" }, /* cdrom is high */
+ { HIGH, PLM_NOFLAGS, 0, "/home/samba" },
+ { HIGH, PLM_NOFLAGS, 0, "/usr/home/samba" },
+ { LOW, PLM_NOFLAGS, 0, "/dev/printer" },
+ { HIGH, PLM_CHILDOF, 0, "/var/log" },
+ { LOW, PLM_NOFLAGS, 0, "/var/log/sendmail.st" },
+ { HIGH, PLM_NOFLAGS, LOWWRITE, "/var/run/utmp" },
+ { HIGH, PLM_NOFLAGS, LOWWRITE, "/var/log/lastlog" },
+ { HIGH, PLM_NOFLAGS, LOWWRITE, "/var/log/wtmp" },
+ { 0, 0, 0 }
+};
+
+#endif /* LOMAC_PLM_H */
diff --git a/sys/security/lomac/syscall_gate.c b/sys/security/lomac/syscall_gate.c
new file mode 100644
index 0000000..56817fc
--- /dev/null
+++ b/sys/security/lomac/syscall_gate.c
@@ -0,0 +1,125 @@
+/*-
+ * Copyright (c) 2001 Networks Associates Technologies, Inc.
+ * All rights reserved.
+ *
+ * This software was developed for the FreeBSD Project 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.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * 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.
+ *
+ * $Id$
+ * $FreeBSD$
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/conf.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/proc.h>
+#include <sys/syscall.h>
+#include <sys/sysent.h>
+
+#include <machine/frame.h>
+
+#include "syscall_gate.h"
+void syscall_gate_init(void);
+int syscall_gate(struct thread *td, caddr_t params);
+
+static struct syscall_gate sg;
+
+void
+syscall_gate_init(void) {
+
+ sg.sg_table = curthread->td_proc->p_sysent->sv_table;
+ bzero(sg.sg_oldsyscalls, sizeof(sg.sg_oldsyscalls));
+}
+
+int
+syscall_gate_register(int offset, sy_call_t *call, int narg, int mpsafe) {
+ struct sysent *se;
+ int error = 0;
+
+ if (offset <= 0 || offset >= SYS_MAXSYSCALL) {
+ error = EINVAL;
+ goto out;
+ }
+ if (sg.sg_oldsyscalls[offset].sy_call != NULL) {
+ error = EEXIST;
+ goto out;
+ }
+ se = &sg.sg_table[offset];
+ sg.sg_oldsyscalls[offset] = *se;
+ se->sy_call = (sy_call_t *)call;
+ se->sy_narg = narg | (mpsafe ? SYF_MPSAFE : 0);
+out:
+ return (error);
+}
+
+void
+syscall_gate_deregister(int offset) {
+ KASSERT(offset > 0 && offset < SYS_MAXSYSCALL, ("syscall offset %d out of range",
+ offset));
+ KASSERT(sg.sg_oldsyscalls[offset].sy_call != NULL, ("deregistering nonexistant syscall %d",
+ offset));
+ sg.sg_table[offset] = sg.sg_oldsyscalls[offset];
+ sg.sg_oldsyscalls[offset].sy_call = NULL;
+ sg.sg_oldsyscalls[offset].sy_narg = 0;
+}
+
+static int
+syscall_gate_modevent(module_t module, int event, void *unused) {
+ int i;
+
+ switch ((enum modeventtype)event) {
+ case MOD_LOAD:
+ syscall_gate_init();
+ break;
+ case MOD_UNLOAD:
+ for (i = 1; i < SYS_MAXSYSCALL; i++) {
+ struct sysent *se;
+
+ se = &sg.sg_oldsyscalls[i];
+ if (se->sy_call != NULL)
+ sg.sg_table[i] = *se;
+ }
+ break;
+ case MOD_SHUTDOWN:
+ break;
+ }
+ return (0);
+}
+
+static moduledata_t syscall_gate_moduledata = {
+ "syscall_gate",
+ &syscall_gate_modevent,
+ NULL
+};
+DECLARE_MODULE(syscall_gate, syscall_gate_moduledata, SI_SUB_DRIVERS, SI_ORDER_ANY);
+MODULE_VERSION(syscall_gate, 1);
diff --git a/sys/security/lomac/syscall_gate.h b/sys/security/lomac/syscall_gate.h
new file mode 100644
index 0000000..9546bea
--- /dev/null
+++ b/sys/security/lomac/syscall_gate.h
@@ -0,0 +1,56 @@
+/*-
+ * Copyright (c) 2001 Networks Associates Technologies, Inc.
+ * All rights reserved.
+ *
+ * This software was developed for the FreeBSD Project 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.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * 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.
+ *
+ * $Id$
+ * $FreeBSD$
+ */
+
+#ifndef SYSCALL_GATE_H
+#define SYSCALL_GATE_H
+
+#include <sys/mutex.h>
+#include <sys/sx.h>
+#include <sys/sysent.h>
+
+#ifdef _KERNEL
+struct syscall_gate {
+ struct sx sg_lock; /* syscalls entered into the kernel */
+ struct sysent *sg_table;
+ struct sysent sg_oldsyscalls[SYS_MAXSYSCALL];
+ struct sysent sg_newsyscalls[SYS_MAXSYSCALL];
+};
+#endif /* _KERNEL */
+
+int syscall_gate_register(int offset, sy_call_t *func, int nargs, int mpsafe);
+void syscall_gate_deregister(int offset);
+#endif /* SYSCALL_GATE_H */
OpenPOWER on IntegriCloud