This commit was generated by cvs2svn to compensate for changes in r86567,

which included commits to RCS files with non-trunk default branches.
This commit is contained in:
Brian Feldman 2001-11-19 04:50:51 +00:00
commit 5eca824ab0
27 changed files with 6577 additions and 0 deletions

View File

@ -0,0 +1,497 @@
/*-
* Copyright (c) 2001 Networks Associates Technology, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 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: kernel_interface.c,v 1.25 2001/10/25 21:21:59 tfraser Exp $
*/
#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);
}

View File

@ -0,0 +1,91 @@
/*-
* Copyright (c) 2001 Networks Associates Technology, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 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: kernel_interface.h,v 1.21 2001/10/15 17:58:32 bfeldman Exp $
*/
#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 */

View File

@ -0,0 +1,279 @@
/*-
* Copyright (c) 2001 Networks Associates Technology, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 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: kernel_lkm.c,v 1.26 2001/11/14 16:30:17 bfeldman Exp $
*/
#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);

View File

@ -0,0 +1,190 @@
/*-
* Copyright (c) 2001 Networks Associates Technology, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 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: kernel_log.c,v 1.12 2001/10/17 15:19:26 bfeldman Exp $
*/
#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() */

View File

@ -0,0 +1,68 @@
/*-
* Copyright (c) 2001 Networks Associates Technology, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 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: kernel_log.h,v 1.5 2001/09/20 21:29:21 tfraser Exp $
*/
#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

View File

@ -0,0 +1,280 @@
/*-
* Copyright (c) 2001 Networks Associates Technology, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 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: kernel_mediate.c,v 1.9 2001/10/17 15:19:40 bfeldman Exp $
*/
/*
* 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() */

View File

@ -0,0 +1,59 @@
/*-
* Copyright (c) 2001 Networks Associates Technology, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 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: kernel_mediate.h,v 1.5 2001/09/26 21:18:00 bfeldman Exp $
*/
#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

View File

@ -0,0 +1,557 @@
/*
* Copyright (c) 2001 Networks Associates Technology, Inc.
* Copyright (c) 1988 University of Utah.
* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* the Systems Programming Group of the University of Utah Computer
* Science Department.
*
* 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
*
* from: Utah $Hdr: vm_mmap.c 1.6 91/10/21$
*
* @(#)vm_mmap.c 8.4 (Berkeley) 1/12/94
* $FreeBSD$
* $Id: kernel_mmap.c,v 1.12 2001/10/17 15:34:29 bfeldman Exp $
*/
#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);
}

View File

@ -0,0 +1,197 @@
/*-
* Copyright (c) 2001 Networks Associates Technology, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 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: kernel_monitor.c,v 1.12 2001/10/16 15:25:02 bfeldman Exp $
*/
/*
* 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);
}

View File

@ -0,0 +1,53 @@
/*-
* Copyright (c) 2001 Networks Associates Technology, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 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: kernel_monitor.h,v 1.5 2001/09/26 23:00:44 tfraser Exp $
*/
#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

View File

@ -0,0 +1,235 @@
/*************************************************************************
*
* kernel_pipe.c
*
* LOMAC - Low Water-Mark Mandatory Access Control
* Copyright (c) 1999-2001 Networks Associates, Inc. All rights reserved.
*
* Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 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.
*
* Neither the name of NAI Labs, Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 REGENTS 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.
*
*
*
* 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() */

View File

@ -0,0 +1,45 @@
#ifndef _KERNEL_PIPE_H_
#define _KERNEL_PIPE_H_
/******************************************************************
*
* kernel_pipe.h
*
* LOMAC - Low Water-Mark Mandatory Access Control
* Copyright (c) 1999-2001 Networks Associates, Inc. All rights reserved.
*
* Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 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.
*
* Neither the name of NAI Labs, Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 REGENTS 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: kernel_pipe.h,v 1.1 2001/09/20 21:29:21 tfraser Exp $
*
* Public interface to kernel_pipe.c, the part of the LOMAC kernel
* interface that takes control of operations on unnamed pipes.
*
*/
int lomac_initialize_pipes( void );
int lomac_uninitialize_pipes( void );
#endif /* _KERNEL_PIPE_H_ */

View File

@ -0,0 +1,373 @@
/*-
* Copyright (c) 2001 Networks Associates Technology, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 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: kernel_plm.c,v 1.9 2001/10/17 15:20:09 bfeldman Exp $
*/
#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);

View File

@ -0,0 +1,35 @@
/*-
* Copyright (c) 2001 Networks Associates Technology, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 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: kernel_plm.h,v 1.4 2001/09/20 17:47:46 bfeldman Exp $
*/
#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 */

View File

@ -0,0 +1,772 @@
/*
* LOMAC - Low Water-Mark Mandatory Access Control
* Copyright (c) 2001 Networks Associates Technology, Inc.
* Copyright (c) 1982, 1986, 1989, 1991, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 REGENTS 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: kernel_socket.c,v 1.9 2001/11/05 20:57:41 tfraser Exp $
*
* 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);
}

View File

@ -0,0 +1,35 @@
/*
* LOMAC - Low Water-Mark Mandatory Access Control
* Copyright (c) 2001 Networks Associates Technology, Inc.
*
* Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 REGENTS 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: kernel_socket.h,v 1.1 2001/09/26 23:00:44 tfraser Exp $
*
*/
#ifndef _KERNEL_SOCKET_H_
#define _KERNEL_SOCKET_H_
int lomac_initialize_sockets( void );
int lomac_uninitialize_sockets( void );
#endif /* _KERNEL_SOCKET_H_ */

View File

@ -0,0 +1,687 @@
/*-
* Copyright (c) 2001 Networks Associates Technology, Inc.
* All rights reserved.
* Copyright (c) 1982, 1986, 1989, 1991, 1993
* The Regents of the University of California. All rights reserved.
* (c) UNIX System Laboratories, Inc.
* 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.
*
* 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: kernel_util.c,v 1.22 2001/11/15 20:51:13 bfeldman Exp $
*/
#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/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);
}

View File

@ -0,0 +1,54 @@
/*-
* Copyright (c) 2001 Networks Associates Technology, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 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: kernel_util.h,v 1.4 2001/11/14 16:30:17 bfeldman Exp $
*/
#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 */

193
sys/contrib/lomac/lomac.h Normal file
View File

@ -0,0 +1,193 @@
/*-
* Copyright (c) 2001 Networks Associates Technology, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 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: lomacfs.h,v 1.20 2001/10/17 15:34:29 bfeldman Exp $
*/
#ifndef _LOMAC_H_
#define _LOMAC_H_
/*
* This file defines the `lattr_t' type, which represents
* the architecture-independent notion of LOMAC attributes.
*
* Each architecture must associate LOMAC attributes with subjects and
* objects. This association can be implemented in an architecture-
* specific way. However, when it comes time to make a decision by
* comparing two LOMAC attributes, the architecture-specific code should
* construct two instances of the architecture-independent lattr_t type
* and compare them using the lomac_must_demote() and lomac_must_deny()
* functions.
*
* The following two examples demonstrate how architecture-specific code
* might do this construction and comparison:
*
* EXAMPLE USAGE:
*
* Example 1: subject x reads object y.
* (1) a = LOMAC attributes of subject x
* (2) b = LOMAC attributes of object y
* (3) demote_result = lomac_must_demote( a, b );
* (4) IF demote_result THEN
* (5) IF subject x is running in "deny read instead of demote" mode THEN
* (6) RETURN read denied
* (7) ENDIF
* (8) IF subject x is not running in "never demote" mode THEN
* (9) demote subject x
* (10) ENDIF
* (11) ENDIF
* (12) perform read on object y
*
*
* Example 2: subject x writes object y.
* (50) a = LOMAC attributes of subject x
* (51) b = LOMAC attributes of object y
* (52) IF lomac_must_deny( a, b ) THEN
* (53) return write denied
* (54) ELSE
* (55) perform write operation on object y
* (56) ENDIF
*
* Lines 1, 2, 50, and 51 show the architecture-specific code
* constructing instances of lattr_t.
*
* Lines 5 and 8 ask "is the subject running in some mode?" (See note
* on modes, below.) The architecture-specific code must use these
* modes to determine when to call lomac_must_demote/deny() and when not
* to.
*
* Lines 6, 9, 53 and 55 show the architecture-specific code
* taking different actions depending on the results of calls to
* lomac_must_demote/deny(). The architecture-specific code is responsible
* for calling lomac_must_demote/deny() in the proper places, and carrying
* out the appropriate demotions and denials depending on the result.
*
*
* A NOTE ON LEVELS:
*
* LOMAC presently supports only two levels: 1 and 2. Future versions
* of LOMAC may support more levels. Architecture-specific code may
* assume that the LOWEST and HIGHEST constants defined below will
* always refer to the lowest and highest levels in the range. They
* may also provide support for only two levels for the time being.
* However, architecture-specific code should try to minimize any other
* assumptions about levels, in order to make it easier to increase
* the level range in the future.
*
*
* A NOTE ON CATEGORIES:
*
* The lattr_t structure's `flags' field is intended to be a bitfield
* which architecture-specific code can use to implement categories.
* The lomac_must_deny() function interprets the bits in the flags field
* as categories. A clear flags field means no categories.
*
* A NOTE ON MODES:
*
* LOMAC allows subjects to run in many modes, such as "never demote"
* or "no demote on IPC reads". Support for these modes is entirely
* the responsibility of the architecture-specific code, because the
* architecture-independent code doesn't know about operations like
* "read" or "read on an IPC object".
*
*************************************************************************/
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 */

106
sys/contrib/lomac/lomacfs.h Normal file
View File

@ -0,0 +1,106 @@
/*-
* Copyright (c) 2001 Networks Associates Technology, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 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: lomacfs.h,v 1.20 2001/10/17 15:34:29 bfeldman Exp $
*/
#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 */

View File

@ -0,0 +1,118 @@
/*-
* Copyright (c) 2001 Networks Associates Technology, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 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: lomacfs_subr.c,v 1.24 2001/11/05 20:57:41 tfraser Exp $
*/
#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);
}

View File

@ -0,0 +1,190 @@
/*-
* Copyright (c) 2001 Networks Associates Technology, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 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: lomacfs_vfsops.c,v 1.16 2001/10/17 19:36:39 bfeldman Exp $
*/
#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);

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,49 @@
/*-
* Copyright (c) 2001 Networks Associates Technology, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 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: lomacio.h,v 1.4 2001/09/26 21:18:00 bfeldman Exp $
*/
#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 */

View File

@ -0,0 +1,110 @@
/*-
* Copyright (c) 2001 Networks Associates Technology, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 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: policy_plm.h,v 1.20 2001/11/15 20:55:05 bfeldman Exp $
*/
#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 */

View File

@ -0,0 +1,116 @@
/*-
* Copyright (c) 2001 Networks Associates Technology, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 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: syscall_gate.c,v 1.4 2001/11/05 21:23:12 bfeldman Exp $
*/
#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);

View File

@ -0,0 +1,47 @@
/*-
* Copyright (c) 2001 Networks Associates Technology, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 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: syscall_gate.h,v 1.2 2001/09/20 17:47:46 bfeldman Exp $
*/
#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 */