diff --git a/sys/security/lomac/kernel_interface.c b/sys/security/lomac/kernel_interface.c index d617523bc0af..adaff99f86ce 100644 --- a/sys/security/lomac/kernel_interface.c +++ b/sys/security/lomac/kernel_interface.c @@ -1,506 +1,506 @@ /*- - * Copyright (c) 2001 Networks Associates Technologies, Inc. + * Copyright (c) 2001 Networks Associates Technology, Inc. * All rights reserved. * * This software was developed for the FreeBSD Project by NAI Labs, the * Security Research Division of Network Associates, Inc. under * DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA * CHATS research program. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $Id$ * $FreeBSD$ */ #include #include #include #include #include #include #include #include #include #include #include #include "kernel_interface.h" #include "lomacfs.h" #include "kernel_log.h" /* * Reuse the eflags field of proc.p_vmspace->vm_map.header (since it is * currently not used for anything but a placeholder, and won't change * generally...) as storage for our process-based information. * * This is the only really effective way to make thread-based MAC * easy. */ #define p_eflags p_vmspace->vm_map.header.eflags #define EF_HIGHEST_LEVEL 0x00010000 #define EF_LOWEST_LEVEL 0x00020000 #define EF_LEVEL_MASK 0x00030000 #define EF_ATTR_NONETDEMOTE 0x00040000 #define EF_ATTR_NODEMOTE 0x00080000 #define EF_ATTR_MASK 0x000c0000 static u_int level2subjectbits(level_t level) { switch (level) { case LOMAC_HIGHEST_LEVEL: return (EF_HIGHEST_LEVEL); case LOMAC_LOWEST_LEVEL: return (EF_LOWEST_LEVEL); default: panic("level2subjectbits: invalid level %d\n", level); } } static level_t subjectbits2level(u_int flags) { switch (flags & EF_LEVEL_MASK) { case EF_HIGHEST_LEVEL: /* * During an execve(), the kernel's original execve() creates a * new vmspace and puts it into use before it has been initialized * by us to contain a subject level. Since this is the only case * when a subject may have a level not set, pretend that it * is just a high-level file, and allow the lomacfs_open() to then * succeed. */ case 0: return (LOMAC_HIGHEST_LEVEL); case EF_LOWEST_LEVEL: return (LOMAC_LOWEST_LEVEL); default: panic("subjectbits2level: invalid flags %#x\n", flags); } } static u_int attr2subjectbits(u_int attr) { u_int bits = 0; if (attr & LOMAC_ATTR_NONETDEMOTE) bits |= EF_ATTR_NONETDEMOTE; if (attr & LOMAC_ATTR_NODEMOTE) bits |= EF_ATTR_NODEMOTE; return (bits); } static u_int subjectbits2attr(u_int bits) { u_int attr = 0; if (bits & EF_ATTR_NONETDEMOTE) attr |= LOMAC_ATTR_NONETDEMOTE; if (bits & EF_ATTR_NODEMOTE) attr |= LOMAC_ATTR_NODEMOTE; return (attr); } static int subject_lock(lomac_subject_t *p, int read) { #ifdef USES_LOCKMGR int hadlock; hadlock = PROC_LOCKED(p); if (hadlock) PROC_UNLOCK(p); #endif if (read) vm_map_lock_read(&p->p_vmspace->vm_map); else vm_map_lock(&p->p_vmspace->vm_map); #ifdef USES_LOCKMGR return (hadlock); #else return (0); #endif } static void subject_unlock(lomac_subject_t *p, int read, int hadlock) { if (read) vm_map_unlock_read(&p->p_vmspace->vm_map); else vm_map_unlock(&p->p_vmspace->vm_map); #ifdef USES_LOCKMGR if (hadlock) PROC_LOCK(p); #endif } void init_subject_lattr(lomac_subject_t *p, lattr_t *lattr) { int s; s = subject_lock(p, 0); p->p_eflags = level2subjectbits(lattr->level) | attr2subjectbits(lattr->flags); subject_unlock(p, 0, s); } /* * Set/get the subject level on a process. The process must not be able * to change, so either the process must be locked on entry or it must * be held in exclusivity otherwise (executing on behalf of via a syscall, * including as EITHER child or parent in a fork). */ void set_subject_lattr(lomac_subject_t *p, lattr_t lattr) { int s; #ifdef INVARIANTS do { lattr_t oslattr; get_subject_lattr(p, &oslattr); if (lomac_must_demote(&lattr, &oslattr)) panic("raising subject level"); } while (0); #endif /* !INVARIANTS */ s = subject_lock(p, 0); p->p_eflags = (p->p_eflags & ~(EF_LEVEL_MASK | EF_ATTR_MASK)) | level2subjectbits(lattr.level) | attr2subjectbits(lattr.flags); subject_unlock(p, 0, s); kernel_vm_drop_perms(curthread, &lattr); } void get_subject_lattr(lomac_subject_t *p, lattr_t *lattr) { int s; s = subject_lock(p, 1); lattr->level = subjectbits2level(p->p_eflags); lattr->flags = subjectbits2attr(p->p_eflags); subject_unlock(p, 1, s); } static __inline u_int level2lvnodebits(level_t level) { switch (level) { case LOMAC_HIGHEST_LEVEL: return (LN_HIGHEST_LEVEL); case LOMAC_LOWEST_LEVEL: return (LN_LOWEST_LEVEL); default: panic("level2lvnodebits: invalid level %d\n", level); } } static __inline level_t lvnodebits2level(u_int flags) { switch (flags & LN_LEVEL_MASK) { case LN_HIGHEST_LEVEL: return (LOMAC_HIGHEST_LEVEL); case LN_LOWEST_LEVEL: return (LOMAC_LOWEST_LEVEL); default: panic("lvnodebits2level: invalid flags %#x\n", flags); } } static __inline unsigned int attr2lvnodebits(unsigned int attr) { unsigned int bits = 0; if (attr & LOMAC_ATTR_LOWWRITE) bits |= LN_ATTR_LOWWRITE; if (attr & LOMAC_ATTR_LOWNOOPEN) bits |= LN_ATTR_LOWNOOPEN; if (attr & LOMAC_ATTR_NONETDEMOTE) bits |= LN_ATTR_NONETDEMOTE; if (attr & LOMAC_ATTR_NODEMOTE) bits |= LN_ATTR_NODEMOTE; return (bits); } static __inline unsigned int lvnodebits2attr(unsigned int bits) { unsigned int attr = 0; if (bits & LN_ATTR_LOWWRITE) attr |= LOMAC_ATTR_LOWWRITE; if (bits & LN_ATTR_LOWNOOPEN) attr |= LOMAC_ATTR_LOWNOOPEN; if (bits & LN_ATTR_NONETDEMOTE) attr |= LOMAC_ATTR_NONETDEMOTE; if (bits & LN_ATTR_NODEMOTE) attr |= LOMAC_ATTR_NODEMOTE; return (attr); } /* * These flags correspond to the same ones set in lomac_node{}s. */ #define UV_LEVEL_MASK 0x08000000 #define UV_LOWEST_LEVEL 0x00000000 #define UV_HIGHEST_LEVEL 0x08000000 #define UV_ATTR_LOWWRITE 0x10000000 #define UV_ATTR_LOWNOOPEN 0x20000000 #define UV_ATTR_NONETDEMOTE 0x40000000 #define UV_ATTR_NODEMOTE 0x80000000 #define UV_ATTR_MASK 0xf0000000 static __inline u_int level2uvnodebits(level_t level) { switch (level) { case LOMAC_HIGHEST_LEVEL: return (UV_HIGHEST_LEVEL); case LOMAC_LOWEST_LEVEL: return (UV_LOWEST_LEVEL); default: panic("level2uvnodebits: invalid level %d\n", level); } } static __inline level_t uvnodebits2level(u_int flags) { switch (flags & UV_LEVEL_MASK) { case UV_HIGHEST_LEVEL: return (LOMAC_HIGHEST_LEVEL); case UV_LOWEST_LEVEL: return (LOMAC_LOWEST_LEVEL); default: panic("uvnodebits2level: invalid flags %#x\n", flags); } } static __inline u_int attr2uvnodebits(u_int attr) { unsigned int bits = 0; if (attr & LOMAC_ATTR_LOWWRITE) bits |= UV_ATTR_LOWWRITE; if (attr & LOMAC_ATTR_LOWNOOPEN) bits |= UV_ATTR_LOWNOOPEN; if (attr & LOMAC_ATTR_NONETDEMOTE) bits |= UV_ATTR_NONETDEMOTE; if (attr & LOMAC_ATTR_NODEMOTE) bits |= UV_ATTR_NODEMOTE; return (bits); } static __inline u_int uvnodebits2attr(u_int bits) { unsigned int attr = 0; if (bits & UV_ATTR_LOWWRITE) attr |= LOMAC_ATTR_LOWWRITE; if (bits & UV_ATTR_LOWNOOPEN) attr |= LOMAC_ATTR_LOWNOOPEN; if (bits & UV_ATTR_NONETDEMOTE) attr |= LOMAC_ATTR_NONETDEMOTE; if (bits & UV_ATTR_NODEMOTE) attr |= LOMAC_ATTR_NODEMOTE; return (attr); } #define OBJ_LOWEST_LEVEL 0x8000 /* the highest level is implicit */ /* * This code marks pipes with levels. We use a previously unnused bit * in the pipe_state field of struct pipe to store the level * information. Bit clear means LOMAC_HIGHEST_LEVEL, bit set means * LOMAC_LOWEST_LEVEL. Since new pipes have clear bits by default, * using clear bit as highest causes new pipes to start at the highest * level automatically. */ #define PIPE_LEVEL_LOWEST 0x10000000 /* This code marks sockets created by socketpair() with levels. It * uses a previouslt unused bit in the so_state field of struct socket * to store the level information. Bit clear means * LOMAC_HIGHEST_LEVEL, bit set means LOMAC_LOWEST_LEVEL. Since new * sockets have clear bits by default, using clear bit as highest * causes new sockets to start at the highest level automatically. */ #define SOCKET_LEVEL_LOWEST 0x4000 void set_object_lattr(lomac_object_t *obj, lattr_t lattr) { struct vnode *vp; struct lomac_node *ln; vm_object_t object; struct pipe *pipe; struct socket *socket; switch (obj->lo_type) { case LO_TYPE_LVNODE: KASSERT(VISLOMAC(obj->lo_object.vnode), ("not a LOMACFS vnode")); ln = VTOLOMAC(obj->lo_object.vnode); ln->ln_flags = (ln->ln_flags & ~(LN_LEVEL_MASK | LN_ATTR_MASK)) | level2lvnodebits(lattr.level) | attr2lvnodebits(lattr.flags); break; case LO_TYPE_UVNODE: vp = obj->lo_object.vnode; KASSERT(!VISLOMAC(vp), ("is a LOMACFS vnode")); VI_LOCK(vp); vp->v_flag = (vp->v_flag & ~(UV_LEVEL_MASK | UV_ATTR_MASK)) | level2uvnodebits(lattr.level) | attr2uvnodebits(lattr.flags); VI_UNLOCK(vp); break; case LO_TYPE_VM_OBJECT: object = obj->lo_object.vm_object; KASSERT(object->type != OBJT_VNODE, ("object has a vnode")); KASSERT(object->backing_object == NULL, ("is a backing object")); if (lattr.level == LOMAC_HIGHEST_LEVEL) vm_object_clear_flag(object, OBJ_LOWEST_LEVEL); else vm_object_set_flag(object, OBJ_LOWEST_LEVEL); KASSERT(lattr.flags == 0, ("cannot set attr on a vm_object")); break; case LO_TYPE_PIPE: pipe = obj->lo_object.pipe; KASSERT(pipe->pipe_peer == NULL || (pipe->pipe_state & PIPE_LEVEL_LOWEST) == (pipe->pipe_peer->pipe_state & PIPE_LEVEL_LOWEST), ("pipe attrs unsynchronized")); if (lattr.level == LOMAC_HIGHEST_LEVEL) pipe->pipe_state &= ~PIPE_LEVEL_LOWEST; else pipe->pipe_state |= PIPE_LEVEL_LOWEST; pipe = pipe->pipe_peer; if (pipe != NULL) { if (lattr.level == LOMAC_HIGHEST_LEVEL) pipe->pipe_state &= ~PIPE_LEVEL_LOWEST; else pipe->pipe_state |= PIPE_LEVEL_LOWEST; } KASSERT(lattr.flags == 0, ("cannot set attr on a pipe")); break; case LO_TYPE_SOCKETPAIR: socket = obj->lo_object.socket; /* KASSERT that socket peer levels are synchronized */ if (lattr.level == LOMAC_HIGHEST_LEVEL) socket->so_state &= ~SOCKET_LEVEL_LOWEST; else socket->so_state |= SOCKET_LEVEL_LOWEST; #ifdef NOT_YET pipe = pipe->pipe_peer; if (pipe != NULL) { if (lattr.level == LOMAC_HIGHEST_LEVEL) pipe->pipe_state &= ~PIPE_LEVEL_LOWEST; else pipe->pipe_state |= PIPE_LEVEL_LOWEST; } KASSERT(lattr.flags == 0, ("cannot set attr on a pipe")); #endif break; default: panic("set_object_lattr: invalid lo_type %d", obj->lo_type); } } void get_object_lattr(const lomac_object_t *obj, lattr_t *lattr) { struct vnode *vp; struct lomac_node *ln; vm_object_t object; struct pipe *pipe; struct socket *socket; switch (obj->lo_type) { case LO_TYPE_LVNODE: KASSERT(VISLOMAC(obj->lo_object.vnode), ("not a LOMACFS vnode")); ln = VTOLOMAC(obj->lo_object.vnode); lattr->level = lvnodebits2level(ln->ln_flags); lattr->flags = lvnodebits2attr(ln->ln_flags); break; case LO_TYPE_UVNODE: vp = obj->lo_object.vnode; KASSERT(!VISLOMAC(vp), ("is a LOMACFS vnode")); VI_LOCK(vp); lattr->level = uvnodebits2level(vp->v_flag); lattr->flags = uvnodebits2attr(vp->v_flag); VI_UNLOCK(vp); break; case LO_TYPE_VM_OBJECT: object = obj->lo_object.vm_object; KASSERT(object->type != OBJT_VNODE, ("object has a vnode")); KASSERT(object->backing_object == NULL, ("is a backing object")); lattr->level = (object->flags & OBJ_LOWEST_LEVEL) ? LOMAC_LOWEST_LEVEL : LOMAC_HIGHEST_LEVEL; lattr->flags = 0; break; case LO_TYPE_PIPE: pipe = obj->lo_object.pipe; lattr->level = (pipe->pipe_state & PIPE_LEVEL_LOWEST) ? LOMAC_LOWEST_LEVEL : LOMAC_HIGHEST_LEVEL; lattr->flags = 0; break; case LO_TYPE_SOCKETPAIR: socket = obj->lo_object.socket; lattr->level = (socket->so_state & SOCKET_LEVEL_LOWEST) ? LOMAC_LOWEST_LEVEL : LOMAC_HIGHEST_LEVEL; lattr->flags = 0; break; default: panic("get_object_level: invalid lo_type %d", obj->lo_type); } } /* * Flag certain procs, like init(8) and kthreads, as "invincible". */ int subject_do_not_demote(lomac_subject_t *subj) { int inv = 0; if (subj->p_pid == 1) { inv = 1; } else { int had_lock = PROC_LOCKED(subj); if (!had_lock) PROC_LOCK(subj); if (subj->p_flag & P_SYSTEM) inv = 1; if (!had_lock) PROC_UNLOCK(subj); } return (inv); } diff --git a/sys/security/lomac/kernel_interface.h b/sys/security/lomac/kernel_interface.h index f9db05eaec76..5229b424ba41 100644 --- a/sys/security/lomac/kernel_interface.h +++ b/sys/security/lomac/kernel_interface.h @@ -1,101 +1,101 @@ /*- - * Copyright (c) 2001 Networks Associates Technologies, Inc. + * Copyright (c) 2001 Networks Associates Technology, Inc. * All rights reserved. * * This software was developed for the FreeBSD Project by NAI Labs, the * Security Research Division of Network Associates, Inc. under * DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA * CHATS research program. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $Id$ * $FreeBSD$ */ #ifndef KERNEL_INTERFACE_H #define KERNEL_INTERFACE_H #include #include #include #include #include #include #include "lomac.h" /* * We do not yet implement any categories. We use lattr_t's flags * field to implement the "LOMAC_ATTR_LOWWRITE" exception. When * this bit is set on a file, lowest-level processes can write to * the file, regardless of the file's level. * * There is also the LOMAC_ATTR_LOWNOOPEN flag, which prevents the * opening of a given object to subjects with a lower level than its * own. * * LOMAC_ATTR_NONETDEMOTE is set on subjects to prevent demotion on * network reads; LOMAC_ATTR_NODEMOTE is set on subjects to prevent * all demotion. Both of these will effectively set a high-level * subject as very trusted (and must be used sparingly). */ #define LOMAC_ATTR_LOWWRITE 0x00010000 #define LOMAC_ATTR_LOWNOOPEN 0x00020000 #define LOMAC_ATTR_NONETDEMOTE 0x00040000 #define LOMAC_ATTR_NODEMOTE 0x00080000 typedef struct proc lomac_subject_t; typedef struct lomac_object { enum lomac_object_type { LO_TYPE_LVNODE, /* LOMAC vnode */ LO_TYPE_UVNODE, /* underlying vnode */ LO_TYPE_VM_OBJECT, /* VM object, not OBJT_VNODE */ LO_TYPE_PIPE, /* pipe */ LO_TYPE_SOCKETPAIR /* local-domain socket in socketpair */ } lo_type; union { struct vnode *vnode; vm_object_t vm_object; struct pipe *pipe; struct socket *socket; } lo_object; } lomac_object_t; typedef struct sbuf lomac_log_t; void init_subject_lattr(lomac_subject_t *, lattr_t *); void set_subject_lattr(lomac_subject_t *, lattr_t); void get_subject_lattr(lomac_subject_t *, lattr_t *); void set_object_lattr(lomac_object_t *, lattr_t); void get_object_lattr(const lomac_object_t *, lattr_t *); int subject_do_not_demote(lomac_subject_t *); #if 0 void subject_propogate_lattr(lomac_subject_t *); #endif void kernel_vm_drop_perms(struct thread *, lattr_t *); #endif /* KERNEL_INTERFACE_H */ diff --git a/sys/security/lomac/kernel_lkm.c b/sys/security/lomac/kernel_lkm.c index 3da6816ca4f7..0455c9c5b8f2 100644 --- a/sys/security/lomac/kernel_lkm.c +++ b/sys/security/lomac/kernel_lkm.c @@ -1,288 +1,288 @@ /*- - * Copyright (c) 2001 Networks Associates Technologies, Inc. + * Copyright (c) 2001 Networks Associates Technology, Inc. * All rights reserved. * * This software was developed for the FreeBSD Project by NAI Labs, the * Security Research Division of Network Associates, Inc. under * DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA * CHATS research program. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $Id$ * $FreeBSD$ */ #include #include #include #include #include #include #include #include #include #include #include #include #include "kernel_interface.h" #include "kernel_mediate.h" #include "kernel_plm.h" #include "kernel_util.h" #include "kernel_pipe.h" #include "kernel_socket.h" #include "lomacfs.h" #include "lomacio.h" static d_ioctl_t lomac_ioctl; #define CDEV_MAJOR 207 #define LOMAC_MINOR 0 static struct cdevsw lomac_cdevsw = { /* open */ (d_open_t *)nullop, /* close */ (d_open_t *)nullop, /* read */ noread, /* write */ nowrite, /* ioctl */ lomac_ioctl, /* poll */ nopoll, /* mmap */ nommap, /* strategy */ nostrategy, /* name */ "lomac", /* maj */ CDEV_MAJOR, /* dump */ nodump, /* psize */ nopsize, /* flags */ 0, }; static dev_t lomac_dev = NULL; int lomac_ioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct thread *td) { struct nameidata nd; struct proc *p; struct proc *targp; struct lomac_fioctl *fio; lomac_object_t lobj; lattr_t lattr; int error; p = td->td_proc; switch (cmd) { case LIOGETPLEVEL: targp = pfind(*(int *)data); if (targp == NULL) return (ESRCH); if (p_cansee(p, targp) != 0) { PROC_UNLOCK(targp); return (ESRCH); } get_subject_lattr(targp, &lattr); *(level_t *)data = lattr.level; PROC_UNLOCK(targp); return (0); case LIOGETFLEVEL: fio = (struct lomac_fioctl *)data; NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | NOOBJ, UIO_SYSSPACE, fio->path, td); if ((error = namei(&nd)) != 0) return (error); if (VISLOMAC(nd.ni_vp)) lobj.lo_type = LO_TYPE_LVNODE; else lobj.lo_type = LO_TYPE_UVNODE; lobj.lo_object.vnode = nd.ni_vp; get_object_lattr(&lobj, &lattr); *(level_t *)&fio->level = lattr.level; NDFREE(&nd, NDF_ONLY_PNBUF); vput(nd.ni_vp); return (error); case LIOGETFLATTR: fio = (struct lomac_fioctl *)data; NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | NOOBJ, UIO_SYSSPACE, fio->path, td); if ((error = namei(&nd)) != 0) return (error); if (VISLOMAC(nd.ni_vp)) lobj.lo_type = LO_TYPE_LVNODE; else lobj.lo_type = LO_TYPE_UVNODE; lobj.lo_object.vnode = nd.ni_vp; get_object_lattr(&lobj, (lattr_t *)&fio->level); NDFREE(&nd, NDF_ONLY_PNBUF); vput(nd.ni_vp); return (error); case LIOPMAKELOWLEVEL: lattr.level = LOMAC_LOWEST_LEVEL; lattr.flags = 0; set_subject_lattr(p, lattr); return (0); default: return (ENOTTY); } } int (*old_execve)(struct proc *, void *); #ifdef __i386__ int (*old_sysarch)(struct proc *, void *); #endif /* * This is "borrowed" from kern_module.c and MUST be kept in synch! */ struct module { TAILQ_ENTRY(module) link; /* chain together all modules */ TAILQ_ENTRY(module) flink; /* all modules in a file */ struct linker_file* file; /* file which contains this module */ int refs; /* reference count */ int id; /* unique id number */ char *name; /* module name */ modeventhand_t handler; /* event handler */ void *arg; /* argument for handler */ modspecific_t data; /* module specific data */ }; static int lomac_modevent(module_t module, int event, void *unused) { static int initialized_procs = 0; static int initialized_syscalls = 0; static int initialized_pipes = 0; static int initialized_sockets = 0; static int initialized_vm = 0; static linker_file_t kernlf; int error; switch ((enum modeventtype)event) { case MOD_LOAD: if (!lomac_plm_initialized) return (EINVAL); kernlf = linker_kernel_file; old_execve = (int (*)(struct proc *, void *))linker_file_lookup_symbol( kernlf, "execve", 1); if (old_execve == NULL) return (ENOENT); #ifdef __i386__ old_sysarch = (int (*)(struct proc *, void *))linker_file_lookup_symbol( kernlf, "sysarch", 1); if (old_sysarch == NULL) return (ENOENT); #endif error = lomac_initialize_procs(); if (error) break; initialized_procs = 1; error = lomac_initialize_syscalls(); if (error) break; initialized_syscalls = 1; error = lomac_initialize_pipes(); if (error) break; initialized_pipes = 1; error = lomac_initialize_sockets(); if (error) break; initialized_sockets = 1; lomac_dev = make_dev(&lomac_cdevsw, LOMAC_MINOR, UID_ROOT, GID_WHEEL, 0666, "lomac"); linker_kernel_file = module->file; error = vfs_mount(curthread, "lomacfs", "/", 0, NULL); if (error) return (error); error = lomac_initialize_cwds(); if (error) return (error); printf("LOMAC: Low-Watermark Mandatory Access Control v2.0.0\n"); return (error); case MOD_UNLOAD: /* * It's always a bad idea to let a low-security process * unload the module providing security. */ if (initialized_procs && !mediate_subject_at_level("kldunload", curthread->td_proc, LOMAC_HIGHEST_LEVEL)) return (EPERM); /* * Unloading doesn't work well at the moment... */ return (EPERM); if (initialized_sockets) { error = lomac_uninitialize_sockets(); if (error) break; initialized_sockets = 0; } if (initialized_pipes) { error = lomac_uninitialize_pipes(); if (error) break; initialized_pipes = 0; } if (initialized_syscalls) { error = lomac_uninitialize_syscalls(); if (error) break; initialized_syscalls = 0; } if (initialized_procs) { error = lomac_uninitialize_procs(); if (error) break; initialized_procs = 0; } if (initialized_vm) { error = lomac_uninitialize_vm(); if (error) break; initialized_vm = 0; } if (lomac_dev) { if (count_dev(lomac_dev) != 0) return (EBUSY); destroy_dev(lomac_dev); } printf("LOMAC: unloading\n"); linker_kernel_file = kernlf; break; case MOD_SHUTDOWN: break; } return (0); } static moduledata_t lomac_moduledata = { "lomac", &lomac_modevent, NULL }; DECLARE_MODULE(lomac, lomac_moduledata, SI_SUB_VFS, SI_ORDER_ANY); MODULE_VERSION(lomac, 1); MODULE_DEPEND(lomac, syscall_gate, 1, 1, 1); MODULE_DEPEND(lomac, lomacfs, 1, 1, 1); MODULE_DEPEND(lomac, lomac_plm, 1, 1, 1); diff --git a/sys/security/lomac/kernel_log.c b/sys/security/lomac/kernel_log.c index a43e70c8f2a2..5e9bf1544356 100644 --- a/sys/security/lomac/kernel_log.c +++ b/sys/security/lomac/kernel_log.c @@ -1,199 +1,199 @@ /*- - * Copyright (c) 2001 Networks Associates Technologies, Inc. + * Copyright (c) 2001 Networks Associates Technology, Inc. * All rights reserved. * * This software was developed for the FreeBSD Project by NAI Labs, the * Security Research Division of Network Associates, Inc. under * DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA * CHATS research program. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $Id$ * $FreeBSD$ */ #include #include #include #include #include #include "lomacfs.h" #include "kernel_interface.h" /* The following definition sets the global log verbosity level. */ SYSCTL_NODE(_kern, OID_AUTO, lomac, CTLFLAG_RW, 0, "LOMAC"); SYSCTL_NODE(_kern_lomac, OID_AUTO, verbose, CTLFLAG_RW, 0, "LOMAC verbosity"); #define VERBOSITY_SETTING(level) \ unsigned int lomac_verbose_##level## = 1; \ SYSCTL_UINT(_kern_lomac_verbose, OID_AUTO, level, \ CTLFLAG_RW, &lomac_verbose_##level##, 1, "") #include "kernel_log.h" /* sbuf_start() * * in: nothing * out: nothing * return: struct sbuf * to pass to later callers * */ lomac_log_t * log_start(void) { struct sbuf *s; s = sbuf_new(NULL, NULL, PATH_MAX * 2, 0); KASSERT(s != NULL, ("sbuf uses M_WAITOK -- must not return NULL!")); return (s); } /* log_start() */ /* log_append_string() * * in: s - a struct sbuf * * in: data_s - null-terminated string to append to log * out: nothing, see description for side-effects * return: nothing * * This function appends `data_s' to `log_s', being careful to ensure * that there is sufficient room in `log_s' for the data and a null * terminator. If there is insufficient room in `log_s' for the entire * `data_s' string, this function will append only the prefix of `data_s' * which fits. * */ void log_append_string(lomac_log_t *s, const char *data_s) { (void)sbuf_cat(s, data_s); } /* log_append_string */ /* log_append_int() * * in: data - integer value to append to log * out: nothing, see description for side-effects * return: nothing * * This function determines the ASCII representation of the integer * value in `data' and, if there is sufficient room, appends this * ASCII representation to `log_s'. If there is insufficient room, * this function behaves as log_append_string(). * */ void log_append_int(lomac_log_t *s, int data) { (void)sbuf_printf(s, "%d", data); } /* log_append_int() */ /* log_append_subject_id() * * in: p_subject - subject whose ID we want to append to the log message * out: nothing, see description for side-effects * return: nothing * * This function appends a string describing the identity of `p_subject' * to `log_s'. If there is insufficient room in `log_s' for the entire * ID string, only a (possibly empty) prefix of the ID string will be * appended. * */ void log_append_subject_id(lomac_log_t *s, const lomac_subject_t *p_subject) { (void)sbuf_printf(s, "p%dg%du%d:%s", p_subject->p_pid, p_subject->p_pgrp->pg_id, p_subject->p_ucred->cr_uid, p_subject->p_comm); } /* log_append_subject_id() */ /* log_append_object_id() * * in: p_object - object whose ID we want to append to the log message * out: nothing, see description for side-effects * return: nothing * * This function appends a string describing the identity of `p_object' * to `log_s'. If there is insufficient room in `log_s' for the entire * ID string, only a (possibly empty) prefix of the ID string will be * appended. * */ void log_append_object_id(lomac_log_t *s, const lomac_object_t *p_object) { struct lomac_node *ln; switch (p_object->lo_type) { case LO_TYPE_UVNODE: (void)sbuf_printf(s, "vp %p", p_object->lo_object.vnode); break; case LO_TYPE_LVNODE: ln = VTOLOMAC(p_object->lo_object.vnode); #ifdef LOMAC_DEBUG_INCNAME (void)sbuf_printf(s, "named \"%s\"", ln->ln_name); #else if (ln->ln_entry != NULL) (void)sbuf_printf(s, "named \"%s\"", ln->ln_entry->ln_path); else (void)sbuf_printf(s, "under \"%s\"", ln->ln_underpolicy->ln_path); #endif break; case LO_TYPE_PIPE: (void)sbuf_printf(s, "pipe %p", p_object->lo_object.pipe); break; case LO_TYPE_SOCKETPAIR: (void)sbuf_printf(s, "socket %p", p_object->lo_object.socket); break; default: panic("invalid LOMAC object type"); } } /* log_append_object_id() */ /* log_print() * * in: nothing * out: nothing * return: nothing * * This function prints `log_s' to the system log. * */ void log_print(lomac_log_t *s) { sbuf_finish(s); log(LOG_INFO, "%s", sbuf_data(s)); sbuf_delete(s); } /* log_print() */ diff --git a/sys/security/lomac/kernel_log.h b/sys/security/lomac/kernel_log.h index c88c12484f96..58dbf9801ef1 100644 --- a/sys/security/lomac/kernel_log.h +++ b/sys/security/lomac/kernel_log.h @@ -1,77 +1,77 @@ /*- - * Copyright (c) 2001 Networks Associates Technologies, Inc. + * Copyright (c) 2001 Networks Associates Technology, Inc. * All rights reserved. * * This software was developed for the FreeBSD Project by NAI Labs, the * Security Research Division of Network Associates, Inc. under * DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA * CHATS research program. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $Id$ * $FreeBSD$ */ #ifndef _KERNEL_LOG_H_ #define _KERNEL_LOG_H_ #include "kernel_interface.h" /* Use this unsigned int and its constants to set the log output * * verbosity. Use of the log_* functions should be surrounded by * * if statements of the form "if( verbose & VERBOSE_FOO )" where * * VERBOSE_FOO is the constant below which corresponds to the * * type of event you're logging. */ #define VERBOSE_NOLOG 0x00000000 /* no log output, please. */ #define VERBOSE_DEMOTE_DENY 0x00000001 /* log demotions and access denials. */ #define VERBOSE_PIPE 0x00000002 /* log changes to pipe "levels". */ #define VERBOSE_LOG_SOCKETS 0x00000004 /* log UNIX domain socket setup. */ #define VERBOSE_LOG_OBJECTS 0x00000008 /* log opening of objects. */ #ifdef TRUST #define VERBOSE_TRUST 0x00000020 /* log when trust stops demotion. */ #endif #ifndef VERBOSITY_SETTING #define VERBOSITY_SETTING(level) extern unsigned int lomac_verbose_##level; #endif VERBOSITY_SETTING(demote_deny); VERBOSITY_SETTING(log_sockets); VERBOSITY_SETTING(log_objects); #ifdef LOMAC_DEBUG_PIPE VERBOSITY_SETTING(pipe); #endif #ifdef TRUST VERBOSITY_SETTING(trust); #endif lomac_log_t *log_start( void ); void log_append_string( lomac_log_t *s, const char *data_s ); void log_append_int( lomac_log_t *s, int data ); void log_append_subject_id( lomac_log_t *s, const lomac_subject_t *p_subject ); void log_append_object_id( lomac_log_t *s, const lomac_object_t *p_object ); void log_print( lomac_log_t *s ); #endif diff --git a/sys/security/lomac/kernel_mediate.c b/sys/security/lomac/kernel_mediate.c index 472dea6c258d..8a8285dd9773 100644 --- a/sys/security/lomac/kernel_mediate.c +++ b/sys/security/lomac/kernel_mediate.c @@ -1,289 +1,289 @@ /*- - * Copyright (c) 2001 Networks Associates Technologies, Inc. + * Copyright (c) 2001 Networks Associates Technology, Inc. * All rights reserved. * * This software was developed for the FreeBSD Project by NAI Labs, the * Security Research Division of Network Associates, Inc. under * DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA * CHATS research program. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $Id$ * $FreeBSD$ */ /* * This file contains functions that make access control decisions * concerning wether or not given system calls should be allowed * or denied. This activity is called "mediation". These functions * generally consider both the parameters passed to a system call * and the current internal state of LOMAC in the course of making * a decision. However, they do not modify these parameters or * LOMAC's internal state. Functions for modifying LOMAC's internal * state can be found in lomac_monitor.c. * */ #include "kernel_interface.h" #include "kernel_mediate.h" #if 0 #include "lomac_plm.h" #endif #include "kernel_log.h" /* mediate_subject_level_subject() * * in: op_s - name of operation to mediate * p_subject_one - subject one (for informational purposes only) * level_one - already-known level of the first subject * p_subject_two - subject two * out: nothing * return: value condition * ----- --------- * 0 caller should deny operation * 1 caller should allow operation * * This function returns 1 if `p_subject_one's level is at least * as great as `p_subject_two's level. Otherwise, it logs a permission * failure on operation `op_s' and returns 0. * * This function is used to mediate pgrp changes. * */ int mediate_subject_level_subject(const char *op_s, const lomac_subject_t *p_subject_one, level_t level_one, lomac_subject_t *p_subject_two) { lattr_t lattr_two; /* lattr of `p_subject_two' */ int ret_val; /* result to return to caller */ #ifdef NO_MEDIATION ret_val = 1; /* no denials, just logging */ #else ret_val = 0; /* pessimistically assume deny */ #endif get_subject_lattr(p_subject_two, &lattr_two); if (lattr_two.level <= level_one) { ret_val = 1; /* OK, allow */ } else if (lomac_verbose_demote_deny) { lomac_log_t *logmsg = log_start(); log_append_string(logmsg, "LOMAC: denied level-"); log_append_int(logmsg, level_one); log_append_string(logmsg, " proc "); log_append_subject_id(logmsg, p_subject_one); log_append_string(logmsg, " "); log_append_string(logmsg, op_s); log_append_string(logmsg, " to level-"); log_append_int(logmsg, lattr_two.level); log_append_string(logmsg, " proc "); log_append_subject_id(logmsg, p_subject_two); log_print(logmsg); } return (ret_val); } /* mediate_subject_subject() */ /* mediate_subject_object() * * in: op_s - string describing operation, like "write" or "writev" * p_subject - subject trying to operate on `p_object'. * p_object - object that `p_subject' is trying to operate on. * out: nothing * return: value condition * ----- --------- * 0 Caller should prevent operation * 1 Caller should permit operation * * This function returns 1 if the level of `p_object' is less than or * equal to the level of `p_subject'. Otherwise, it returns 0 and * logs a permission denial on `op_s'. * * This function allows LOMAC to mediate write and writev system calls. * */ int mediate_subject_object(const char *op_s, lomac_subject_t *p_subject, const lomac_object_t *p_object) { lattr_t subject_lattr; /* lattr of `p_subject' */ lattr_t object_lattr; /* lattr of `p_object' */ int ret_val; /* value to return to caller */ #ifdef NO_MEDIATION ret_val = 1; /* allow operation regardless of decision */ #else ret_val = 0; /* pessimistically assume deny */ #endif /* Get the lattrs of `p_subject' and `p_object' so we can compare them. */ get_subject_lattr(p_subject, &subject_lattr); get_object_lattr(p_object, &object_lattr); /* * If `p_subject's level is less than `p_object's level, * we indicate that the operation must not be allowed. */ if (!lomac_must_deny(&subject_lattr, &object_lattr) || object_lattr.flags & LOMAC_ATTR_LOWWRITE) { ret_val = 1; /* allow operation */ } else if (lomac_verbose_demote_deny) { lomac_log_t *logmsg = log_start(); log_append_string(logmsg, "LOMAC: level-"); log_append_int(logmsg, subject_lattr.level); log_append_string(logmsg, " proc "); log_append_subject_id(logmsg, p_subject); log_append_string(logmsg, " denied "); log_append_string(logmsg, op_s); log_append_string(logmsg, " to level-"); log_append_int(logmsg, object_lattr.level); log_append_string(logmsg, " object "); log_append_object_id(logmsg, p_object); log_append_string(logmsg, "\n"); log_print(logmsg); } return (ret_val); } /* mediate_subject_object() */ /* mediate_subject_object_open() * * in: p_subject - subject trying to operate on `p_object'. * p_object - object that `p_subject' is trying to operate on. * out: nothing * return: value condition * ----- --------- * 0 Caller should prevent operation * 1 Caller should permit operation * * This function returns 1 if the level of `p_object' is less than or * equal to the level of `p_subject'. Otherwise, it returns 0 and * logs a permission denial on `op_s'. * * This function allows LOMAC to mediate open system calls. * */ int mediate_subject_object_open(lomac_subject_t *p_subject, const lomac_object_t *p_object) { lattr_t subject_lattr; /* lattr of `p_subject' */ lattr_t object_lattr; /* lattr of `p_object' */ int ret_val; /* value to return to caller */ #ifdef NO_MEDIATION ret_val = 1; /* allow operation regardless of decision */ #else ret_val = 0; /* pessimistically assume deny */ #endif /* Get the lattrs of `p_subject' and `p_object' so we can compare them. */ get_subject_lattr(p_subject, &subject_lattr); get_object_lattr(p_object, &object_lattr); /* * If `p_subject's level is less than `p_object's level, * we must indicate that the operation should not be allowed. */ if (lomac_must_deny(&subject_lattr, &object_lattr) && object_lattr.flags & LOMAC_ATTR_LOWNOOPEN) { if (lomac_verbose_demote_deny) { lomac_log_t *logmsg = log_start(); log_append_string(logmsg, "LOMAC: level-"); log_append_int(logmsg, subject_lattr.level); log_append_string(logmsg, " proc "); log_append_subject_id(logmsg, p_subject); log_append_string(logmsg, " denied open to level-"); log_append_int(logmsg, object_lattr.level); log_append_string(logmsg, " object "); log_append_object_id(logmsg, p_object); log_append_string(logmsg, "\n"); log_print(logmsg); } } else { ret_val = 1; /* allow operation */ } /* if/else allow/deny */ return (ret_val); } /* mediate_subject_object() */ /* mediate_subject_at_level() * * in: op_s - name of operation being mediated * p_subject - subject whose level we want to check * target_level - level to compare to `p_subject's level * * out: nothing * return: value condition * ----- --------- * 0 `p_subject' is not at `target_level' * 1 `p_subject' is at `target_level' * * This function provides a predicate for determining whether or not * `p_subject' is at the level specified by `target_level'. This * function compares `p_subject's level to `target_level'. If the * levels match, it retruns 1. Otherwise, it logs a permission denial * on `op_s' and returns 0. * */ int mediate_subject_at_level(const char *op_s, lomac_subject_t *p_subject, const level_t target_level) { lattr_t subject_lattr; /* lattr of `p_subject' */ int ret_val; /* value returned to caller */ #ifdef NO_MEDIATION ret_val = 1; /* allow operation regardless of decision */ #else ret_val = 0; /* pessimistically assume deny */ #endif /* Make `subject_lattr' the lattr of `p_subject'. */ get_subject_lattr(p_subject, &subject_lattr); /* compare with `target_lattr */ if (subject_lattr.level == target_level) { ret_val = 1; /* allow operation */ } else if (lomac_verbose_demote_deny) { lomac_log_t *logmsg = log_start(); log_append_string(logmsg, "LOMAC: denied level-"); log_append_int(logmsg, subject_lattr.level); log_append_string(logmsg, " proc "); log_append_subject_id(logmsg, p_subject); log_append_string(logmsg, "'s "); log_append_string(logmsg, op_s); log_append_string(logmsg, ".\n"); log_print(logmsg); } return (ret_val); } /* mediate_subject_at_level() */ diff --git a/sys/security/lomac/kernel_mediate.h b/sys/security/lomac/kernel_mediate.h index 23c24e2a1add..37842e64b67b 100644 --- a/sys/security/lomac/kernel_mediate.h +++ b/sys/security/lomac/kernel_mediate.h @@ -1,68 +1,68 @@ /*- - * Copyright (c) 2001 Networks Associates Technologies, Inc. + * Copyright (c) 2001 Networks Associates Technology, Inc. * All rights reserved. * * This software was developed for the FreeBSD Project by NAI Labs, the * Security Research Division of Network Associates, Inc. under * DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA * CHATS research program. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $Id$ * $FreeBSD$ */ #ifndef _KERNEL_MEDIATE_H_ #define _KERNEL_MEDIATE_H_ #include "kernel_interface.h" int mediate_subject_level_subject( const char *op_s, const lomac_subject_t *p_subject_one, level_t level_one, lomac_subject_t *p_subject_two ); int mediate_subject_object( const char *op_s, lomac_subject_t *p_subject, const lomac_object_t *p_object ); int mediate_subject_object_open( lomac_subject_t *p_subject, const lomac_object_t *p_object ); #if 0 int mediate_subject_path( const char *op_s, const lomac_subject_t *p_subject, const char *path_s ); int mediate_path_path( const char *op_s, const lomac_subject_t *p_subject, const char *canabsname_one_s, const char *canabsname_two_s ); #endif int mediate_subject_at_level( const char *op_s, lomac_subject_t *p_subject, const level_t target_level ); #if 0 int mediate_object_at_level( const char *op_s, const lomac_subject_t *p_subject, const lomac_object_t *p_object, const level_t target_level ); #endif #endif diff --git a/sys/security/lomac/kernel_mmap.c b/sys/security/lomac/kernel_mmap.c index 40d53e6a3776..72e31eea450a 100644 --- a/sys/security/lomac/kernel_mmap.c +++ b/sys/security/lomac/kernel_mmap.c @@ -1,591 +1,591 @@ /*- - * Copyright (c) 2001 Networks Associates Technologies, Inc. + * Copyright (c) 2001 Networks Associates Technology, Inc. * All rights reserved. * * This software was developed for the FreeBSD Project by NAI Labs, the * Security Research Division of Network Associates, Inc. under * DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA * CHATS research program. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the the above entities nor the names of any * contributors of those entities may be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $Id$ */ /* * 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$ */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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, td->td_ucred, td))) { goto done; } if ((va.va_flags & (SF_SNAPSHOT|IMMUTABLE|APPEND)) == 0) { maxprot |= VM_PROT_WRITE; } else if (prot & PROT_WRITE) { error = EPERM; goto done; } } else if ((prot & PROT_WRITE) != 0) { error = EACCES; goto done; } } else { maxprot |= VM_PROT_WRITE; } handle = (void *)vp; origvp = vp; } } /* * Do not allow more then a certain number of vm_map_entry structures * per process. Scale with the number of rforks sharing the map * to make the limit reasonable for threads. */ if (max_proc_mmap && vms->vm_map.nentries >= max_proc_mmap * vms->vm_refcnt) { error = ENOMEM; goto done; } mtx_unlock(&Giant); error = 0; if (handle != NULL && VISLOMAC(origvp)) { lobj.lo_type = LO_TYPE_LVNODE; lobj.lo_object.vnode = origvp; if (flags & MAP_SHARED && maxprot & VM_PROT_WRITE && !mediate_subject_object("mmap", p, &lobj)) error = EPERM; if (error == 0 && maxprot & VM_PROT_READ) error = monitor_read_object(p, &lobj); } if (error == 0) error = vm_mmap(&vms->vm_map, &addr, size, prot, maxprot, flags, handle, pos); if (error == 0) td->td_retval[0] = (register_t) (addr + pageoff); mtx_lock(&Giant); done: if (fp) fdrop(fp, td); mtx_unlock(&Giant); return (error); } static void vm_drop_perms_recurse(struct thread *td, struct vm_map *map, lattr_t *lattr) { struct vm_map_entry *vme; for (vme = map->header.next; vme != &map->header; vme = vme->next) { if (vme->eflags & MAP_ENTRY_IS_SUB_MAP) { vm_map_lock_read(vme->object.sub_map); vm_drop_perms_recurse(td, vme->object.sub_map, lattr); vm_map_unlock_read(vme->object.sub_map); continue; } if ((vme->eflags & (MAP_ENTRY_COW | MAP_ENTRY_NOSYNC)) == 0 && vme->max_protection & VM_PROT_WRITE) { vm_object_t object; vm_ooffset_t offset; lomac_object_t lobj; struct vnode *vp; lattr_t olattr; offset = vme->offset; object = vme->object.vm_object; if (object == NULL) continue; while (object->backing_object) { object = object->backing_object; offset += object->backing_object_offset; } /* * Regular objects (swap, etc.) inherit from * their creator. Vnodes inherit from their * underlying on-disk object. */ if (object->type == OBJT_DEVICE) continue; if (object->type == OBJT_VNODE) { vp = lobj.lo_object.vnode = object->handle; /* * For the foreseeable future, an OBJT_VNODE * is always !VISLOMAC(). */ lobj.lo_type = VISLOMAC(vp) ? LO_TYPE_LVNODE : LO_TYPE_UVNODE; } else { vp = NULL; lobj.lo_object.vm_object = object; lobj.lo_type = LO_TYPE_VM_OBJECT; } get_object_lattr(&lobj, &olattr); /* * Revoke write access only to files with a higher * level than the process or which have a possibly- * undeterminable level (interpreted as "lowest"). */ if (lomac_must_deny(lattr, &olattr)) continue; vm_map_lock_upgrade(map); /* * If it's a private, non-file-backed mapping and * not mapped anywhere else, we can just take it * down with us. */ if (vp == NULL && object->flags & OBJ_ONEMAPPING) { olattr.level = lattr->level; set_object_lattr(&lobj, olattr); goto downgrade; } if ((vme->protection & VM_PROT_WRITE) == 0) vme->max_protection &= ~VM_PROT_WRITE; else { vm_object_reference(object); if (vp != NULL) vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); vm_object_page_clean(object, OFF_TO_IDX(offset), OFF_TO_IDX(offset + vme->end - vme->start + PAGE_MASK), OBJPC_SYNC); if (vp != NULL) VOP_UNLOCK(vp, 0, td); vm_object_deallocate(object); vme->eflags |= MAP_ENTRY_COW | MAP_ENTRY_NEEDS_COPY; pmap_protect(map->pmap, vme->start, vme->end, vme->protection & ~VM_PROT_WRITE); vm_map_simplify_entry(map, vme); } downgrade: vm_map_lock_downgrade(map); } } } void kernel_vm_drop_perms(struct thread *td, lattr_t *newlattr) { struct vm_map *map = &td->td_proc->p_vmspace->vm_map; mtx_lock(&Giant); vm_map_lock_read(map); vm_drop_perms_recurse(td, map, newlattr); vm_map_unlock_read(map); mtx_unlock(&Giant); } /* * Take the level of new vm_objects from the parent subject's level. */ static void vm_object_init_lattr(vm_object_t object) { lomac_object_t lobj; lattr_t lattr; get_subject_lattr(curthread->td_proc, &lattr); lattr.flags = 0; lobj.lo_type = LO_TYPE_VM_OBJECT; lobj.lo_object.vm_object = object; set_object_lattr(&lobj, lattr); } #define PGO_ALLOC_REPLACEMENT(n) \ static vm_object_t (*old_pgo_alloc_##n)(void *, vm_ooffset_t, \ vm_prot_t, vm_ooffset_t); \ \ static vm_object_t \ pgo_alloc_##n(void *handle, vm_ooffset_t size, vm_prot_t prot, \ vm_ooffset_t off) { \ vm_object_t newobj = NULL; \ \ newobj = old_pgo_alloc_##n(handle, size, prot, off); \ if (newobj != NULL) \ vm_object_init_lattr(newobj); \ return (newobj); \ } #define PGO_ALLOC_REPLACE(n) \ do { \ old_pgo_alloc_##n = pagertab[n]->pgo_alloc; \ if (pagertab[n]->pgo_alloc != NULL) \ pagertab[n]->pgo_alloc = pgo_alloc_##n; \ } while (0) #define PGO_ALLOC_UNREPLACE(n) \ do { \ pagertab[n]->pgo_alloc = old_pgo_alloc_##n; \ } while (0) PGO_ALLOC_REPLACEMENT(0); PGO_ALLOC_REPLACEMENT(1); PGO_ALLOC_REPLACEMENT(2); PGO_ALLOC_REPLACEMENT(3); PGO_ALLOC_REPLACEMENT(4); PGO_ALLOC_REPLACEMENT(5); extern int npagers; int lomac_initialize_vm(void) { GIANT_REQUIRED; if (npagers != 6) { printf("LOMAC: number of pagers %d not expected 6!\n", npagers); return (EDOM); } PGO_ALLOC_REPLACE(0); PGO_ALLOC_REPLACE(1); PGO_ALLOC_REPLACE(2); PGO_ALLOC_REPLACE(3); PGO_ALLOC_REPLACE(4); PGO_ALLOC_REPLACE(5); return (0); } int lomac_uninitialize_vm(void) { GIANT_REQUIRED; PGO_ALLOC_UNREPLACE(0); PGO_ALLOC_UNREPLACE(1); PGO_ALLOC_UNREPLACE(2); PGO_ALLOC_UNREPLACE(3); PGO_ALLOC_UNREPLACE(4); PGO_ALLOC_UNREPLACE(5); return (0); } diff --git a/sys/security/lomac/kernel_monitor.c b/sys/security/lomac/kernel_monitor.c index 3568680a6720..443c6095e19f 100644 --- a/sys/security/lomac/kernel_monitor.c +++ b/sys/security/lomac/kernel_monitor.c @@ -1,206 +1,206 @@ /*- - * Copyright (c) 2001 Networks Associates Technologies, Inc. + * Copyright (c) 2001 Networks Associates Technology, Inc. * All rights reserved. * * This software was developed for the FreeBSD Project by NAI Labs, the * Security Research Division of Network Associates, Inc. under * DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA * CHATS research program. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $Id$ * $FreeBSD$ */ /* * This file contains functions which update LOMAC's internal * state in response to system events, such as successful * system calls. These updates allow LOMAC to keep an accurate * picture of the kernel's state, enabling LOMAC to make reasonable * decisions when it mediates processes' use of security-relevant * system calls. These functions perform no mediation themselves - * that is, they do not make access control decisions concerning * whether a given system call should be allowed or denied. This * mediation is handled by the functions in lomac_mediate.c. */ #include "kernel_interface.h" #include "kernel_monitor.h" #include "kernel_log.h" #include "kernel_util.h" /* monitor_read_object() * * in: p_subject - subject that read `p_object'. * p_object - object read by `p_subject'. * out: nothing * return: nothing * * This function examines the objects read by subjects. If a subject * reads from an object with a level lower than its own, this function * reduces the subject's level to match the object's. This lowering * is referred to as "demotion" in much of the LOMAC documentation. * This function performs no mediation. * * This function is for the following kinds of objects: * regular files and FIFOs. * It is also used to monitor reads on unnamed pipes. LOMAC does not * consider unnamed pipes to be objects, and treats them differently * from objects such as files. However, the differences are mostly * in the write-handling behavior. LOMAC's read-handling behavior is * the same both for objects and unnamed pipes, so this function * handles both cases. */ int monitor_read_object(lomac_subject_t *p_subject, lomac_object_t *p_object) { lattr_t subject_lattr; /* lattr of `p_subject' */ lattr_t object_lattr; /* lattr of `p_object' */ /* Get the lattrs of `p_subject' and `p_object' so we can compare them. */ get_subject_lattr(p_subject, &subject_lattr); get_object_lattr(p_object, &object_lattr); /* * If `p_object's level is less than `p_subject's level, * we must demote `p_subject'. The level may be 0 to indicate * existence before LOMAC started. */ if (object_lattr.level && lomac_must_demote(&subject_lattr, &object_lattr) && (subject_lattr.flags & LOMAC_ATTR_NODEMOTE) == 0) { if (subject_do_not_demote(p_subject)) return (0); set_subject_lattr(p_subject, object_lattr); /* demote! */ if (lomac_verbose_demote_deny) { lomac_log_t *s = log_start(); log_append_string(s, "LOMAC: level-"); log_append_int(s, subject_lattr.level); log_append_string(s, " subject "); log_append_subject_id(s, p_subject); log_append_string(s, " demoted to level "); log_append_int(s, object_lattr.level); log_append_string(s, " after reading "); log_append_object_id(s, p_object); log_append_string(s, "\n"); log_print(s); } } /* if we need to demote */ return (0); } /* monitor_read_object() */ /* monitor_pipe_write() * * in: p_subject - subject that just wrote to `p_pipe'. * p_pipe - pipe `p_subject' has written to. * out: p_pipe - pipe may have its level adjusted. * return: 0 * * This function should be called after a successful write to * `p_pipe'. If the level of `p_subject' is less than the level of * `p_pipe', this function reduces `p_pipe's level to match * `current's. * * */ int monitor_pipe_write(lomac_subject_t *p_subject, lomac_object_t *p_pipe) { lattr_t pipe_lattr; /* lattr of `p_pipe' */ lattr_t subject_lattr; /* lattr of `p_subject' */ get_subject_lattr(p_subject, &subject_lattr); get_object_lattr(p_pipe, &pipe_lattr); if (lomac_must_demote(&pipe_lattr, &subject_lattr)) { subject_lattr.flags = 0; set_object_lattr(p_pipe, subject_lattr); #ifdef LOMAC_DEBUG_PIPE if (lomac_verbose_pipe) { lomac_log_t *s = log_start(); log_append_string(s, "LOMAC: level-"); log_append_int(s, subject_lattr.level); log_append_string(s, " subject "); log_append_subject_id(s, p_subject); log_append_string(s, " contaminated level-"); log_append_int(s, pipe_lattr.level); log_append_string(s, " "); log_append_object_id(s, p_pipe); log_append_string(s, "\n"); log_print(s); } #endif /* LOMAC_DEBUG_PIPE */ } return (0); } /* monitor_pipe_write() */ /* monitor_read_net_socket() * * in: p_subject - subject that read from network socket. * out: nothing * return: 0 * * */ int monitor_read_net_socket(lomac_subject_t *p_subject) { lattr_t subject_lattr; /* lattr of `p_subject' */ lattr_t socket_lattr; /* lattr of socket (always lowest) */ socket_lattr.level = LOMAC_LOWEST_LEVEL; socket_lattr.flags = 0; get_subject_lattr(p_subject, &subject_lattr); if (lomac_must_demote(&subject_lattr, &socket_lattr) && (subject_lattr.flags & (LOMAC_ATTR_NODEMOTE | LOMAC_ATTR_NONETDEMOTE)) == 0) { if (subject_do_not_demote(p_subject)) return (0); socket_lattr.flags = subject_lattr.flags; set_subject_lattr(p_subject, socket_lattr); /* demote! */ if (lomac_verbose_demote_deny) { lomac_log_t *s = log_start(); log_append_string(s, "LOMAC: level-"); log_append_int(s, subject_lattr.level); log_append_string(s, " subject "); log_append_subject_id(s, p_subject); log_append_string(s, " demoted to level "); log_append_int(s, socket_lattr.level); log_append_string(s, " after reading from " "the network\n"); log_print(s); } } return (0); } diff --git a/sys/security/lomac/kernel_monitor.h b/sys/security/lomac/kernel_monitor.h index a429465ce150..e7237bf84541 100644 --- a/sys/security/lomac/kernel_monitor.h +++ b/sys/security/lomac/kernel_monitor.h @@ -1,62 +1,62 @@ /*- - * Copyright (c) 2001 Networks Associates Technologies, Inc. + * Copyright (c) 2001 Networks Associates Technology, Inc. * All rights reserved. * * This software was developed for the FreeBSD Project by NAI Labs, the * Security Research Division of Network Associates, Inc. under * DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA * CHATS research program. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $Id$ * $FreeBSD$ */ #ifndef _LOMAC_MONITOR_H_ #define _LOMAC_MONITOR_H_ int monitor_read_object( lomac_subject_t *, lomac_object_t * ); int monitor_pipe_write( lomac_subject_t *, lomac_object_t * ); int monitor_read_net_socket( lomac_subject_t *p_subject ); #if 0 void monitor_open( lomac_subject_t *p_subject, lomac_object_t *p_object ); void monitor_pipe_create( lomac_subject_t *p_subject, lomac_object_t *p_pipe ); void monitor_unix_socket_bind( lomac_subject_t *p_subject, lomac_object_t *p_socket, lomac_object_t *p_name ); void monitor_unix_socket_abstract( lomac_subject_t *p_subject, lomac_object_t *p_socket ); void monitor_unix_socketpair( lomac_subject_t *p_subject, lomac_object_t *p_socket1, lomac_object_t *p_socket2 ); void monitor_unix_socket_accept_connect( lomac_subject_t *p_subject, lomac_object_t *p_old_socket, lomac_object_t *p_new_socket ); #endif #endif diff --git a/sys/security/lomac/kernel_pipe.c b/sys/security/lomac/kernel_pipe.c index 4df9f086b127..3aee257587da 100644 --- a/sys/security/lomac/kernel_pipe.c +++ b/sys/security/lomac/kernel_pipe.c @@ -1,241 +1,241 @@ /*- - * Copyright (c) 2001 Networks Associates Technologies, Inc. + * Copyright (c) 2001 Networks Associates Technology, Inc. * All rights reserved. * * This software was developed for the FreeBSD Project by NAI Labs, the * Security Research Division of Network Associates, Inc. under * DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA * CHATS research program. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $Id$ * $FreeBSD$ */ /* * This file contains part of LOMAC's interface to the kernel. This * part allows LOMAC to monitor (unnamed) pipe read and write * operations by interposing control on the kernel's pipeops vector. * * The pipeops vector is defined in kern/sys_pipe.c. * * USAGE: * * The LOMAC LKM should call lomac_initialize_pipes() at LKM load time. * This function turns unnamed pipe interposition on by modifying * the function addresses in pipeops. * * Once the LOMAC LKM turns interposition on, all reads and writes * will pass through this file's monitoring functions. * * This file provides a lomac_uninitialize_pipes() function which * turns unnamed pipe interposition off by restoring pipeops to * its original unmodified state. Once the LOMAC LKM turns * interposition off, subsequent unnamed pipe reads and writes * will not pass through this file's monitoring functions. * * HOW LOMAC HANDLES PIPES: * * (This text describes how LOMAC handles (unnamed) pipes in terms of * abstract architecture-independent concepts.) LOMAC does not treat * pipes as objects, as it does files. When the kernel creates a new * pipe, LOMAC assigns it the highest level. Whenever a process * writes to the pipe, LOMAC reduces the pipe's level to match the * level of the writing process. Whenever a process reads from a * pipe, LOMAC reduces the level of the reading process to match the * pipe's level. As a result, if a high-level process reads the * output of a low-level process through a pipe, the reading process * will wind up at the low level. * * It takes two `struct pipe's to make a pipe. We set the level * information in both `struct pipes', and keep them synchronized. * * This code presently relies on the one-big-kernel-lock to * synchronize its access to the `pipe_state' field of each `struct * pipe'. * */ #include #include #include #include #include #include #include #include #include #include "lomac.h" #include "kernel_interface.h" #include "kernel_monitor.h" #include "kernel_pipe.h" /* `pipeops' is the kernel's pipe operations vector for the file * * structure. All reads and writes to pipes call through this vector. */ extern struct fileops pipeops; /* defined in kern/sys_pipe.c */ /* These vars store the original addresses of the pipeops read and * * write operations, so we can call them, and even restore them * * later if we want to. */ static int (*pipe_read_orig)(struct file *, struct uio *, struct ucred *, int, struct thread *); static int (*pipe_write_orig)(struct file *, struct uio *, struct ucred *, int, struct thread *); /* declarations of functions private to this module: */ static int lomac_pipe_read(struct file *, struct uio *, struct ucred *, int, struct thread *); static int lomac_pipe_write(struct file *, struct uio *, struct ucred *, int, struct thread *); /* -------------------- public functions ---------------------------- */ /* lomac_initialize_pipes() * * in: nothing * out: nothing * return: 0 * * Turns pipe interposition on by replacing the pipe_read() and pipe_write() * operations in the kernel's pipeops vector with lomac_pipe_read() and * lomac_pipe_write(). Saves the addresses of the original operations * so other functions can call them, and so pipe_interposition_off() * can restore the pipeops vector to its original unmodified state. * */ int lomac_initialize_pipes(void) { pipe_read_orig = pipeops.fo_read; pipeops.fo_read = lomac_pipe_read; pipe_write_orig = pipeops.fo_write; pipeops.fo_write = lomac_pipe_write; return (0); } /* lomac_initialize_pipes() */ /* lomac_uninitialize_pipes() * * in: nothing * out: nothing * return: 0 * * Turns pipe interposition off by restoring the pipeops vector to its * original unmodified state. * * See note at top of file regarding this function and unloading the * LOMAC LKM. * */ int lomac_uninitialize_pipes(void) { KASSERT(pipe_read_orig, ("LOMAC:pipe interpositon off before on")); KASSERT(pipe_write_orig, ("LOMAC:pipe interpositon off before on")); pipeops.fo_read = pipe_read_orig; pipeops.fo_write = pipe_write_orig; return (0); } /* lomac_uninitialize_pipes() */ /* ------------------- private functions --------------------------- */ #ifndef MIN #define MIN(lo, mac) ((lo) < (mac) ? (lo) : (mac)) #endif /* lomac_pipe_read() * * Passes the read operation down to pipe_read_orig(). If * pipe_read_orig() returns success, examines the level of the pipe * and the reading process. If the reading process has a higher * level, reduces the level of the process to equal the pipe's level. * */ static int lomac_pipe_read(struct file *fp, struct uio *uio, struct ucred *cred, int flags, struct thread *td) { lomac_object_t read_pipe; /* attrs are in read end of pipe */ struct uio kuio; struct iovec kiov; void *buf; int len; int ret_val; /* holds return values */ len = MIN(uio->uio_resid, BIG_PIPE_SIZE); kiov.iov_base = buf = malloc(len, M_TEMP, M_WAITOK); kiov.iov_len = len; kuio.uio_iov = &kiov; kuio.uio_iovcnt = 1; kuio.uio_offset = 0; kuio.uio_resid = len; kuio.uio_segflg = UIO_SYSSPACE; kuio.uio_rw = UIO_READ; kuio.uio_td = td; ret_val = pipe_read_orig(fp, &kuio, cred, flags, td); if (ret_val == 0) { read_pipe.lo_type = LO_TYPE_PIPE; read_pipe.lo_object.pipe = (struct pipe *)fp->f_data; (void)monitor_read_object(td->td_proc, &read_pipe); ret_val = uiomove(buf, len - kuio.uio_resid, uio); } free(buf, M_TEMP); return (ret_val); } /* lomac_pipe_read() */ /* lomac_pipe_write() * * Passes the write operation down to pipe_write_orig(). If * pipe_write_orig() returns success, examines the level of the pipe * and the writing process. If the pipe has a higher level than the * writing process, this function reduces the pipe's level to equal * the level of the writing process. * */ static int lomac_pipe_write(struct file *fp, struct uio *uio, struct ucred *cred, int flags, struct thread *td) { lomac_object_t pipe; int ret_val; /* holds return values */ pipe.lo_type = LO_TYPE_PIPE; pipe.lo_object.pipe = (struct pipe *)fp->f_data; ret_val = monitor_pipe_write(td->td_proc, &pipe); if (ret_val == 0) ret_val = pipe_write_orig(fp, uio, cred, flags, td); return (ret_val); } /* lomac_pipe_write() */ diff --git a/sys/security/lomac/kernel_pipe.h b/sys/security/lomac/kernel_pipe.h index de1d01ca95db..1dc268badb99 100644 --- a/sys/security/lomac/kernel_pipe.h +++ b/sys/security/lomac/kernel_pipe.h @@ -1,44 +1,44 @@ /*- - * Copyright (c) 2001 Networks Associates Technologies, Inc. + * Copyright (c) 2001 Networks Associates Technology, Inc. * All rights reserved. * * This software was developed for the FreeBSD Project by NAI Labs, the * Security Research Division of Network Associates, Inc. under * DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA * CHATS research program. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $Id$ * $FreeBSD$ */ #ifndef _KERNEL_PIPE_H_ #define _KERNEL_PIPE_H_ int lomac_initialize_pipes( void ); int lomac_uninitialize_pipes( void ); #endif /* _KERNEL_PIPE_H_ */ diff --git a/sys/security/lomac/kernel_plm.c b/sys/security/lomac/kernel_plm.c index 138670444a7e..060f3fcedfb2 100644 --- a/sys/security/lomac/kernel_plm.c +++ b/sys/security/lomac/kernel_plm.c @@ -1,382 +1,382 @@ /*- - * Copyright (c) 2001 Networks Associates Technologies, Inc. + * Copyright (c) 2001 Networks Associates Technology, Inc. * All rights reserved. * * This software was developed for the FreeBSD Project by NAI Labs, the * Security Research Division of Network Associates, Inc. under * DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA * CHATS research program. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $Id$ * $FreeBSD$ */ #include #include #include #include #include #include #include #include #include "kernel_interface.h" #include "kernel_plm.h" #include "lomacfs.h" #include "policy_plm.h" MALLOC_DEFINE(M_LOMACPLM, "LOMAC_PLM", "LOMAC PLM nodes and strings"); char *strsep(register char **stringp, register const char *delim); /* * Get next token from string *stringp, where tokens are possibly-empty * strings separated by characters from delim. * * Writes NULs into the string at *stringp to end tokens. * delim need not remain constant from call to call. * On return, *stringp points past the last NUL written (if there might * be further tokens), or is NULL (if there are definitely no more tokens). * * If *stringp is NULL, strsep returns NULL. */ char * strsep(stringp, delim) register char **stringp; register const char *delim; { register char *s; register const char *spanp; register int c, sc; char *tok; if ((s = *stringp) == NULL) return (NULL); for (tok = s;;) { c = *s++; spanp = delim; do { if ((sc = *spanp++) == c) { if (c == 0) s = NULL; else s[-1] = 0; *stringp = s; return (tok); } } while (sc != 0); } /* NOTREACHED */ } struct lomac_node_entry lomac_node_entry_root = { SLIST_HEAD_INITIALIZER(lomac_node_entry), { NULL }, LN_HIGHEST_LEVEL | LN_INHERIT_HIGH, "/" }; static struct lomac_node_entry * lomac_plm_subtree_find_cnp(struct lomac_node_entry *root, struct componentname *cnp) { char *nameptr = cnp->cn_nameptr; struct lomac_node_entry *lne; int len = cnp->cn_namelen; SLIST_FOREACH(lne, &root->ln_children, ln_chain) if (strlen(lne->ln_name) == len && bcmp(lne->ln_name, nameptr, len) == 0) break; return (lne); } static struct lomac_node_entry * lomac_plm_subtree_find(struct lomac_node_entry *root, const char *name) { struct lomac_node_entry *lne; SLIST_FOREACH(lne, &root->ln_children, ln_chain) if (strcmp(name, lne->ln_name) == 0) break; return (lne); } /* * This is called from inside getnewvnode() before the vnode is in use. */ void lomac_plm_init_lomacfs_vnode(struct vnode *dvp, struct vnode *vp, struct componentname *cnp, lattr_t *subjlattr) { struct lomac_node *ln = VTOLOMAC(vp); struct lomac_node_entry *mlne = NULL; /* * Only "/" has no parent, so inherit directly from our PLM root. */ if (dvp == NULL) { ln->ln_flags = lomac_node_entry_root.ln_flags; ln->ln_entry = ln->ln_underpolicy = &lomac_node_entry_root; } else { struct lomac_node *dln = VTOLOMAC(dvp); struct lomac_node_entry *dlne = dln->ln_entry; int fixup_inherit = 0; /* * If we have no directory-specific entry, we inherit * directly from the lomac_node's previously-inherited * flags implicitly, otherwise we inherit explicitly * from the corresponding lomac_node_entry. */ if (dlne == NULL) { ln->ln_flags = dln->ln_flags & LN_INHERIT_MASK; fixup_inherit = 1; ln->ln_underpolicy = dln->ln_underpolicy; ln->ln_entry = NULL; } else if ((mlne = lomac_plm_subtree_find_cnp(dlne, cnp)) == NULL) { ln->ln_flags = dlne->ln_flags & LN_INHERIT_MASK; fixup_inherit = 2; ln->ln_underpolicy = dlne; ln->ln_entry = NULL; } else { ln->ln_entry = ln->ln_underpolicy = mlne; } if (fixup_inherit) { switch (ln->ln_flags) { case LN_INHERIT_LOW: ln->ln_flags |= LN_LOWEST_LEVEL; break; case LN_INHERIT_SUBJ: if (subjlattr->level == LOMAC_HIGHEST_LEVEL) ln->ln_flags |= LN_HIGHEST_LEVEL; else { ln->ln_flags &= ~LN_INHERIT_MASK; ln->ln_flags |= LN_INHERIT_LOW | LN_LOWEST_LEVEL; } break; case LN_INHERIT_HIGH: ln->ln_flags |= LN_HIGHEST_LEVEL; break; } if (fixup_inherit == 2) ln->ln_flags |= (dlne->ln_flags & LN_CHILD_ATTR_MASK) >> LN_CHILD_ATTR_SHIFT; } else { /* this is the only case where mlne != NULL */ ln->ln_flags &= ~(LN_INHERIT_MASK | LN_ATTR_MASK); ln->ln_flags |= mlne->ln_flags & (LN_INHERIT_MASK | LN_ATTR_MASK); if ((mlne->ln_flags & LN_LEVEL_MASK) == LN_SUBJ_LEVEL) { if (subjlattr->level == LOMAC_HIGHEST_LEVEL) ln->ln_flags |= LN_HIGHEST_LEVEL; else ln->ln_flags |= LN_LOWEST_LEVEL; } else ln->ln_flags |= mlne->ln_flags & LN_LEVEL_MASK; } } KASSERT(ln->ln_flags & LN_LEVEL_MASK, ("lomac_node has no level")); KASSERT(ln->ln_flags & LN_INHERIT_MASK, ("lomac_node has no inherit")); #ifdef INVARIANTS if (mlne != NULL) { KASSERT(mlne->ln_flags & LN_LEVEL_MASK, ("lomac_node_entry has no level")); KASSERT(mlne->ln_flags & LN_INHERIT_MASK, ("lomac_node_entry has no inherit")); } #endif /* INVARIANTS */ } static struct lomac_node_entry * lomac_plm_subtree_new(struct lomac_node_entry *plne, char *name) { struct lomac_node_entry *lne; static struct lomac_node_entry_head head_init = SLIST_HEAD_INITIALIZER(lomac_node_entry); lne = malloc(sizeof(*lne), M_LOMACPLM, M_WAITOK); bcopy(&head_init, &lne->ln_children, sizeof(head_init)); lne->ln_name = name; lne->ln_flags = plne->ln_flags & LN_INHERIT_MASK; switch (lne->ln_flags) { case LN_INHERIT_LOW: lne->ln_flags |= LN_LOWEST_LEVEL; break; case LN_INHERIT_HIGH: lne->ln_flags |= LN_HIGHEST_LEVEL; break; case LN_INHERIT_SUBJ: lne->ln_flags |= LN_SUBJ_LEVEL; break; } SLIST_INSERT_HEAD(&plne->ln_children, lne, ln_chain); return (lne); } static void lomac_plm_subtree_free(struct lomac_node_entry *lneself) { struct lomac_node_entry_head *head = &lneself->ln_children; struct lomac_node_entry *lne; while (!SLIST_EMPTY(head)) { lne = SLIST_FIRST(head); SLIST_REMOVE_HEAD(head, ln_chain); lomac_plm_subtree_free(lne); } free(lneself, M_LOMACPLM); } struct string_list { SLIST_ENTRY(string_list) entries; char string[1]; }; static SLIST_HEAD(, string_list) string_list_head = SLIST_HEAD_INITIALIZER(string_list); static char * string_list_new(const char *s) { struct string_list *sl; sl = malloc(sizeof(*sl) + strlen(s), M_LOMACPLM, M_WAITOK); strcpy(sl->string, s); SLIST_INSERT_HEAD(&string_list_head, sl, entries); return (sl->string); } static void lomac_plm_uninitialize(void) { struct lomac_node_entry_head *head = &lomac_node_entry_root.ln_children; struct lomac_node_entry *lne; struct string_list *sl; while (!SLIST_EMPTY(head)) { lne = SLIST_FIRST(head); SLIST_REMOVE_HEAD(head, ln_chain); lomac_plm_subtree_free(lne); } while (!SLIST_EMPTY(&string_list_head)) { sl = SLIST_FIRST(&string_list_head); SLIST_REMOVE_HEAD(&string_list_head, entries); free(sl, M_LOMACPLM); } } static int lomac_plm_initialize(void) { struct lomac_node_entry *plne, *lne; plm_rule_t *pr; for (pr = plm; pr->path != NULL; pr++) { char *path; char *comp; int depth; if (*pr->path == '\0') { printf("lomac_plm: invalid path \"%s\"\n", pr->path); return (EINVAL); } path = string_list_new(pr->path); lne = &lomac_node_entry_root; depth = 0; for (;; depth++) { plne = lne; comp = strsep(&path, "/"); if (comp == NULL) break; if (depth == 0) { /* special case: beginning / */ if (*comp == '\0') continue; else { printf("lomac_plm: not absolute path " "\"%s\"\n", pr->path); return (EINVAL); } } else if (depth == 1) { /* special case: "/" */ if (*comp == '\0' && strsep(&path, "/") == NULL) break; } if (*comp == '\0' || strcmp(comp, ".") == 0 || strcmp(comp, "..") == 0) { printf("lomac_plm: empty path component in " "\"%s\"\n", pr->path); return (EINVAL); } lne = lomac_plm_subtree_find(plne, comp); if (lne == NULL) { lne = lomac_plm_subtree_new(plne, comp); lne->ln_path = plne->ln_path; } } lne->ln_path = pr->path; if (pr->flags == PLM_NOFLAGS) lne->ln_flags &= ~LN_LEVEL_MASK; else lne->ln_flags &= ~LN_INHERIT_MASK; lne->ln_flags |= plm_levelflags_to_node_flags[pr->level][pr->flags]; if (pr->flags == PLM_NOFLAGS) lne->ln_flags |= pr->attr; else lne->ln_flags |= (pr->attr & LN_ATTR_MASK) << LN_CHILD_ATTR_SHIFT; } return (0); } int lomac_plm_initialized = 0; static int lomac_plm_modevent(module_t module, int event, void *unused) { int error = 0; switch ((enum modeventtype)event) { case MOD_LOAD: error = lomac_plm_initialize(); if (error == 0) lomac_plm_initialized = 1; break; case MOD_UNLOAD: lomac_plm_uninitialize(); case MOD_SHUTDOWN: break; } return (error); } static moduledata_t lomac_plm_moduledata = { "lomac_plm", &lomac_plm_modevent, NULL }; DECLARE_MODULE(lomac_plm, lomac_plm_moduledata, SI_SUB_VFS, SI_ORDER_ANY); MODULE_VERSION(lomac_plm, 1); diff --git a/sys/security/lomac/kernel_plm.h b/sys/security/lomac/kernel_plm.h index 8676d06a0cf7..2b0db12a3086 100644 --- a/sys/security/lomac/kernel_plm.h +++ b/sys/security/lomac/kernel_plm.h @@ -1,45 +1,45 @@ /*- - * Copyright (c) 2001 Networks Associates Technologies, Inc. + * Copyright (c) 2001 Networks Associates Technology, Inc. * All rights reserved. * * This software was developed for the FreeBSD Project by NAI Labs, the * Security Research Division of Network Associates, Inc. under * DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA * CHATS research program. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $Id$ * $FreeBSD$ */ #ifndef KERNEL_PLM_H #define KERNEL_PLM_H extern int lomac_plm_initialized; /* set to 1 if successfully initialized */ void lomac_plm_init_lomacfs_vnode(struct vnode *dvp, struct vnode *vp, struct componentname *cnp, lattr_t *subjlattr); #endif /* KERNEL_PLM_H */ diff --git a/sys/security/lomac/kernel_socket.c b/sys/security/lomac/kernel_socket.c index cc432a0aa1ae..291ccc2e97e9 100644 --- a/sys/security/lomac/kernel_socket.c +++ b/sys/security/lomac/kernel_socket.c @@ -1,813 +1,813 @@ /*- - * Copyright (c) 2001 Networks Associates Technologies, Inc. + * Copyright (c) 2001 Networks Associates Technology, Inc. * * This software was developed for the FreeBSD Project by NAI Labs, the * Security Research Division of Network Associates, Inc. under * DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA * CHATS research program. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the the above entities nor the names of any * contributors of those entities may be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $Id$ */ /* * Copyright (c) 1982, 1986, 1988, 1990, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. 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. * * @(#)uipc_socket.c 8.3 (Berkeley) 4/15/94 * $FreeBSD$ */ /* * This file implements LOMAC controls over socket operations. LOMAC * gains control of socket operations by interposing on the `struct * pr_usrreqs' operations vectors of each `struct protosw'. This code * replaces each `struct pr_usrreqs' with an instance of `struct * lomac_pr_usrreqs' containing LOMAC socket control functions. These * socket control functions implement LOMAC's socket controls, and then * call the corresponding socket operations from the original `struct * pr_usrreqs'. Each instance of `struct lomac_pr_usrreqs' ends with * a pointer to the `struct pr_usrreqs' it replaces. These pointers * allow the LOMAC socket control functions to find their corresponding * original `struct pr_usrreqs' functions. * * This file provides the function lomac_initialize_sockets() to turn * socket interposition on. Once socket iterposition is turned on, * the kernel will begin to call LOMAC's socket control functions. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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_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 = sonewconn(so2, 0)) == 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). */ cru2x(td->td_ucred, &unp3->unp_peercred); 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); so->so_rcv.sb_mb = m_free(m); 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 { so->so_rcv.sb_mb = m_free(m); m = so->so_rcv.sb_mb; } if (m) m->m_nextpkt = nextrecord; } } else { if (flags & MSG_PEEK) moff += len; else { if (mp) *mp = m_copym(m, 0, len, M_TRYWAIT); m->m_data += len; m->m_len -= len; so->so_rcv.sb_cc -= len; } } if (so->so_oobmark) { if ((flags & MSG_PEEK) == 0) { so->so_oobmark -= len; if (so->so_oobmark == 0) { so->so_state |= SS_RCVATMARK; break; } } else { offset += len; if (offset == so->so_oobmark) break; } } if (flags & MSG_EOR) break; /* * If the MSG_WAITALL flag is set (for non-atomic socket), * we must not quit until "uio->uio_resid == 0" or an error * termination. If a signal/timeout occurs, return * with a short count but without error. * Keep sockbuf locked against other readers. */ while (flags & MSG_WAITALL && m == 0 && uio->uio_resid > 0 && !sosendallatonce(so) && !nextrecord) { if (so->so_error || so->so_state & SS_CANTRCVMORE) break; /* * Notify the protocol that some data has been * drained before blocking. */ if (pr->pr_flags & PR_WANTRCVD && so->so_pcb) (*pr->pr_usrreqs->pru_rcvd)(so, flags); error = sbwait(&so->so_rcv); if (error) { sbunlock(&so->so_rcv); splx(s); return (0); } m = so->so_rcv.sb_mb; if (m) nextrecord = m->m_nextpkt; } } if (m && pr->pr_flags & PR_ATOMIC) { flags |= MSG_TRUNC; if ((flags & MSG_PEEK) == 0) (void) sbdroprecord(&so->so_rcv); } if ((flags & MSG_PEEK) == 0) { if (m == 0) so->so_rcv.sb_mb = nextrecord; if (pr->pr_flags & PR_WANTRCVD && so->so_pcb) (*pr->pr_usrreqs->pru_rcvd)(so, flags); } if (orig_resid == uio->uio_resid && orig_resid && (flags & MSG_EOR) == 0 && (so->so_state & SS_CANTRCVMORE) == 0) { sbunlock(&so->so_rcv); splx(s); goto restart; } if (flagsp) *flagsp |= flags; release: sbunlock(&so->so_rcv); splx(s); return (error); } diff --git a/sys/security/lomac/kernel_socket.h b/sys/security/lomac/kernel_socket.h index 4343c19b6f43..f4f7ccb360ee 100644 --- a/sys/security/lomac/kernel_socket.h +++ b/sys/security/lomac/kernel_socket.h @@ -1,45 +1,45 @@ /*- - * Copyright (c) 2001 Networks Associates Technologies, Inc. + * Copyright (c) 2001 Networks Associates Technology, Inc. * All rights reserved. * * This software was developed for the FreeBSD Project by NAI Labs, the * Security Research Division of Network Associates, Inc. under * DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA * CHATS research program. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $Id$ * $FreeBSD$ */ #ifndef _KERNEL_SOCKET_H_ #define _KERNEL_SOCKET_H_ int lomac_initialize_sockets( void ); int lomac_uninitialize_sockets( void ); #endif /* _KERNEL_SOCKET_H_ */ diff --git a/sys/security/lomac/kernel_util.c b/sys/security/lomac/kernel_util.c index 8a57a2b61242..21e4a7c24deb 100644 --- a/sys/security/lomac/kernel_util.c +++ b/sys/security/lomac/kernel_util.c @@ -1,695 +1,695 @@ /*- - * Copyright (c) 2001 Networks Associates Technologies, Inc. + * Copyright (c) 2001 Networks Associates Technology, Inc. * Copyright (c) 1982, 1986, 1989, 1991, 1993 * The Regents of the University of California. All rights reserved. * (c) UNIX System Laboratories, Inc. * This software was developed for the FreeBSD Project by NAI Labs, the * Security Research Division of Network Associates, Inc. under * DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA * CHATS research program. * * All or some portions of this file are derived from material licensed * to the University of California by American Telephone and Telegraph * Co. or Unix System Laboratories, Inc. and are reproduced herein with * the permission of UNIX System Laboratories, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $Id$ * $FreeBSD$ */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kernel_interface.h" #include "kernel_util.h" #include "kernel_mediate.h" #include "kernel_monitor.h" #include "lomacfs.h" #include "syscall_gate.h" #define AS(name) (sizeof(struct name) / sizeof(register_t)) int each_proc(int (*iter)(struct proc *p)) { struct proc *p; int error = 0; sx_slock(&allproc_lock); LIST_FOREACH(p, &allproc, p_list) { error = (*iter)(p); if (error) goto out; } out: sx_sunlock(&allproc_lock); return (error); } static int initialize_proc(struct proc *p) { lattr_t lattr = { LOMAC_HIGHEST_LEVEL, 0 }; init_subject_lattr(p, &lattr); return (0); } static void lomac_at_fork(struct proc *parent, struct proc *p, int flags) { if ((flags & RFMEM) == 0) { lattr_t parent_lattr; get_subject_lattr(parent, &parent_lattr); init_subject_lattr(p, &parent_lattr); } } static int lomac_proc_candebug(struct proc *p1, struct proc *p2) { lattr_t lattr; get_subject_lattr(p1, &lattr); if (mediate_subject_level_subject("debug", p1, lattr.level, p2)) return (0); else return (EPERM); } static int lomac_proc_cansched(struct proc *p1, struct proc *p2) { lattr_t lattr; get_subject_lattr(p1, &lattr); if (mediate_subject_level_subject("sched", p1, lattr.level, p2)) return (0); else return (EPERM); } static int lomac_proc_cansignal(struct proc *p1, struct proc *p2, int signum) { lattr_t lattr; get_subject_lattr(p1, &lattr); /* * Always allow signals to init(8) (necessary to shut down). */ if (p2->p_pid == 1 || mediate_subject_level_subject("signal", p1, lattr.level, p2)) return (0); else return (EPERM); } int lomac_initialize_procs(void) { int error; #ifdef P_CAN_HOOKS can_hooks_lock(); (void)p_candebug_hook(lomac_proc_candebug); (void)p_cansignal_hook(lomac_proc_cansignal); (void)p_cansched_hook(lomac_proc_cansched); can_hooks_unlock(); #endif error = at_fork(lomac_at_fork); if (error) return (error); return (each_proc(&initialize_proc)); } int lomac_uninitialize_procs(void) { rm_at_fork(lomac_at_fork); return (0); } extern int (*old_execve)(struct thread *, struct execve_args *); int execve(struct thread *td, struct execve_args *uap) { lattr_t lattr, textattr; struct vmspace *oldvmspace; struct proc *p; int error; p = td->td_proc; get_subject_lattr(p, &lattr); oldvmspace = p->p_vmspace; error = old_execve(td, uap); if (error == 0) { lomac_object_t lobj; lobj.lo_type = VISLOMAC(p->p_textvp) ? LO_TYPE_LVNODE : LO_TYPE_UVNODE; lobj.lo_object.vnode = p->p_textvp; get_object_lattr(&lobj, &textattr); /* * Install the executable's relevant attributes into the * process. */ lattr.flags |= textattr.flags & (LOMAC_ATTR_NODEMOTE | LOMAC_ATTR_NONETDEMOTE); if (p->p_vmspace != oldvmspace) init_subject_lattr(p, &lattr); else set_subject_lattr(p, lattr); mtx_lock(&Giant); (void)monitor_read_object(p, &lobj); mtx_unlock(&Giant); } return (error); } const char *linker_basename(const char* path); int linker_load_module(const char *kldname, const char *modname, struct linker_file *parent, struct mod_depend *verinfo, struct linker_file **lfpp); MALLOC_DECLARE(M_LINKER); /* * MPSAFE */ int kldload(struct thread* td, struct kldload_args* uap) { char *kldname, *modname; char *pathname = NULL; linker_file_t lf; int error = 0; td->td_retval[0] = -1; if (securelevel > 0) /* redundant, but that's OK */ return EPERM; mtx_lock(&Giant); if ((error = suser_td(td)) != 0) goto out; pathname = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); if ((error = copyinstr(SCARG(uap, file), pathname, MAXPATHLEN, NULL)) != 0) goto out; if (!mediate_subject_at_level("kldload", td->td_proc, LOMAC_HIGHEST_LEVEL)) { error = EPERM; goto out; } /* * If path do not contain qualified name or any dot in it (kldname.ko, or * kldname.ver.ko) treat it as interface name. */ if (index(pathname, '/') || index(pathname, '.')) { kldname = pathname; modname = NULL; } else { kldname = NULL; modname = pathname; } error = linker_load_module(kldname, modname, NULL, NULL, &lf); if (error) goto out; lf->userrefs++; td->td_retval[0] = lf->id; out: if (pathname) free(pathname, M_TEMP); mtx_unlock(&Giant); return (error); } #ifdef __i386__ #include 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_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 = FIRST_THREAD_IN_PROC(p); /* XXXKSE Only one? */ 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_ucred, curthread); if (error) vput(vp); else { NDFREE(&nd, NDF_ONLY_PNBUF); fdp = p->p_fd; cdir = fdp->fd_cdir; fdp->fd_cdir = vp; vrele(cdir); VOP_UNLOCK(vp, 0, curthread); } } #if defined(LOMAC_DEBUG_RECWD) printf("\trecwd() to \"%.*s\" == %d\n", MAXPATHLEN, nbuf, error); #endif return (0); } int lomac_initialize_cwds(void) { int error; pathmem = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); direntmem = malloc(DIRENTMEM_SIZE, M_TEMP, M_WAITOK); mtx_lock(&Giant); error = each_proc(lomac_do_recwd); mtx_unlock(&Giant); free(pathmem, M_TEMP); free(direntmem, M_TEMP); return (error); } diff --git a/sys/security/lomac/kernel_util.h b/sys/security/lomac/kernel_util.h index f3480ed5d911..9663688741e9 100644 --- a/sys/security/lomac/kernel_util.h +++ b/sys/security/lomac/kernel_util.h @@ -1,64 +1,64 @@ /*- - * Copyright (c) 2001 Networks Associates Technologies, Inc. + * Copyright (c) 2001 Networks Associates Technology, Inc. * All rights reserved. * * This software was developed for the FreeBSD Project by NAI Labs, the * Security Research Division of Network Associates, Inc. under * DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA * CHATS research program. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $Id$ * $FreeBSD$ */ #ifndef KERNEL_UTIL_H #define KERNEL_UTIL_H /* * Iterate through each proc, locking it and calling iter. * Short-circuit and return an error if the iterator ever returns one. */ int each_proc(int (*iter)(struct proc *p)); /* * Set the initial level on each proc, register at_fork(). */ int lomac_initialize_procs(void); /* * Unregister at_fork(). */ int lomac_uninitialize_procs(void); int lomac_initialize_cwds(void); int lomac_initialize_syscalls(void); int lomac_uninitialize_syscalls(void); int lomac_initialize_vm(void); int lomac_uninitialize_vm(void); #endif /* KERNEL_UTIL_H */ diff --git a/sys/security/lomac/lomac.h b/sys/security/lomac/lomac.h index b891fb1bf850..331a3b529218 100644 --- a/sys/security/lomac/lomac.h +++ b/sys/security/lomac/lomac.h @@ -1,114 +1,114 @@ /*- - * Copyright (c) 2001 Networks Associates Technologies, Inc. + * Copyright (c) 2001 Networks Associates Technology, Inc. * All rights reserved. * * This software was developed for the FreeBSD Project by NAI Labs, the * Security Research Division of Network Associates, Inc. under * DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA * CHATS research program. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #ifndef LOMAC_H_ #define LOMAC_H_ typedef enum { LOMAC_LOWEST_LEVEL = 1, LOMAC_HIGHEST_LEVEL = 2 } level_t; typedef struct { level_t level; /* level (an integer range) */ unsigned int flags; /* category flags */ } lattr_t; /* lomac attribute structure type */ /* lomac_must_demote() * * in: actor - attributes of a subject that has or will perform an * operation that may require LOMAC to demote it. * target - attributes of the object that is or was the operand. * out: nothing * return: value condition * ----- --------- * 0 LOMAC should not demote the subject * 1 LOMAC should demote the subject * * This function is a predicate which decides whether or not LOMAC should * demote the subject with attributes `actor' after it performs an operation * (probably some kind of a read operation) on the object with attributes * `target'. * */ static __inline int lomac_must_demote(const lattr_t *actor, const lattr_t *target) { return (actor->level > target->level); } /* lomac_must_deny() * * in: actor - attributes of a subject that wants to perform some * operation that requires LOMAC to make an allow/deny * decision. * target - attributes of the subject or object the above subject * will operate upon. * out: nothing * return: value condition * ----- --------- * 0 LOMAC should allow the operation * 1 LOMAC should deny the operation * * This function is a predicate which decides whether or not LOMAC should * allow the subject with attributes `actor' to perform some operation * (probably some kind of write or kill operation) on the subject or object * with attributes `target'. * * The flags are two words: the low word is to be used for categories, * and the high word is meant to hold implementation-dependent flags that * are not category-related. * */ static __inline int lomac_must_deny(const lattr_t *actor, const lattr_t *target) { if (actor->level >= target->level) return 0; /* allow */ if (target->flags & 0xffff) { if ((actor->flags & target->flags & 0xffff) == (target->flags & 0xffff)) { return 0; /* allow */ } } return 1; /* deny */ } #endif /* LOMAC_H */ diff --git a/sys/security/lomac/lomacfs.h b/sys/security/lomac/lomacfs.h index b14414685b74..575a98c63c10 100644 --- a/sys/security/lomac/lomacfs.h +++ b/sys/security/lomac/lomacfs.h @@ -1,115 +1,115 @@ /*- - * Copyright (c) 2001 Networks Associates Technologies, Inc. + * Copyright (c) 2001 Networks Associates Technology, Inc. * All rights reserved. * * This software was developed for the FreeBSD Project by NAI Labs, the * Security Research Division of Network Associates, Inc. under * DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA * CHATS research program. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $Id$ * $FreeBSD$ */ #ifndef LOMACFS_H #define LOMACFS_H #include #include #include #include #include #include "kernel_interface.h" struct lomac_mount { struct vnode *lm_rootvp; /* singly-ref'd root after mount() */ #define LM_TOOKROOT 0x0001 unsigned int lm_flags; }; /* * This is the structure associated with v_data on all LOMACFS vnodes. */ struct lomac_node { struct vnode *ln_vp; /* vnode back-pointer */ struct vnode *ln_lowervp; /* shadowed vnode (ref'd or NULL) */ #define LN_LEVEL_MASK 0x0003 #define LN_LOWEST_LEVEL 0x0001 #define LN_SUBJ_LEVEL 0x0002 /* placeholder before inheriting */ #define LN_HIGHEST_LEVEL 0x0003 #define LN_INHERIT_MASK 0x001c #define LN_INHERIT_LOW 0x0004 /* children start with a low level */ #define LN_INHERIT_HIGH 0x0008 /* children start with a high level */ #define LN_INHERIT_SUBJ 0x0010 /* children inherit subject's level */ #define LN_ATTR_MASK 0x01e0 #define LN_ATTR_LOWWRITE 0x0020 /* lower levels may write to */ #define LN_ATTR_LOWNOOPEN 0x0040 /* lower levels may not open */ #define LN_ATTR_NONETDEMOTE 0x0080 /* will not demote on net read */ #define LN_ATTR_NODEMOTE 0x0100 /* subject won't demote on other read */ u_int ln_flags; /* What's the last node explicitly specifying policy for this? */ struct lomac_node_entry *ln_underpolicy; /* If non-NULL, this corresponds 1:1 to a specific PLM node entry. */ struct lomac_node_entry *ln_entry; #if defined(LOMAC_DEBUG_INCNAME) char ln_name[MAXPATHLEN]; /* final component name */ #endif }; /* * This is the "placeholder" structure initialized from the PLM that * holds the level information for all named objects. */ struct lomac_node_entry { SLIST_HEAD(lomac_node_entry_head, lomac_node_entry) ln_children; SLIST_ENTRY(lomac_node_entry) ln_chain; /* chain of current level */ /* continuing with the LN_* flags above */ #define LN_CHILD_ATTR_SHIFT 4 /* lshift from attr -> child attr */ #define LN_CHILD_ATTR_MASK 0x1e00 #define LN_CHILD_ATTR_LOWWRITE 0x0200 /* lower levels may write to */ #define LN_CHILD_ATTR_LOWNOOPEN 0x0400 /* lower levels may not open */ #define LN_CHILD_ATTR_NONETDEMOTE 0x0800 /* will not demote on net read */ #define LN_CHILD_ATTR_NODEMOTE 0x1000 /* subject won't demote on other read */ u_int ln_flags; char *ln_name; /* last component name (to search) */ const char *ln_path; /* in "stable" storage */ }; #define VTOLOMAC(vp) ((struct lomac_node *)(vp)->v_data) #define VTOLVP(vp) VTOLOMAC(vp)->ln_lowervp #define VFSTOLOMAC(mp) ((struct lomac_mount *)mp->mnt_data) #define VISLOMAC(vp) (vp->v_op == lomacfs_vnodeop_p) int lomacfs_node_alloc(struct mount *mp, struct componentname *cnp, struct vnode *dvp, struct vnode *lowervp, struct vnode **vpp); MALLOC_DECLARE(M_LOMACFS); extern vop_t **lomacfs_vnodeop_p; extern struct lomac_node_entry lomac_node_entry_root; #endif /* LOMACFS_H */ diff --git a/sys/security/lomac/lomacfs_subr.c b/sys/security/lomac/lomacfs_subr.c index fd7df03049f0..1bd559d6e446 100644 --- a/sys/security/lomac/lomacfs_subr.c +++ b/sys/security/lomac/lomacfs_subr.c @@ -1,127 +1,127 @@ /*- - * Copyright (c) 2001 Networks Associates Technologies, Inc. + * Copyright (c) 2001 Networks Associates Technology, Inc. * All rights reserved. * * This software was developed for the FreeBSD Project by NAI Labs, the * Security Research Division of Network Associates, Inc. under * DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA * CHATS research program. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $Id$ * $FreeBSD$ */ #include #include #include #include #include #include #include #include "lomacfs.h" #include "kernel_plm.h" int lomacfs_node_alloc(struct mount *mp, struct componentname *cnp, struct vnode *dvp, struct vnode *lowervp, struct vnode **vpp) { lomac_object_t lobj; struct thread *td = curthread; struct vnode *vp; struct lomac_node *lp; lattr_t subjlattr, objlattr; int error; KASSERT((cnp == NULL) == (dvp == NULL), ("lomacfs_node_alloc: dvp and cnp do not match")); lp = malloc(sizeof(*lp), M_LOMACFS, M_WAITOK); if (dvp != NULL) { error = cache_lookup(dvp, vpp, cnp); if (error == -1) { /* lost the race; return EEXIST and the vp */ vput(lowervp); error = vget(*vpp, LK_EXCLUSIVE, td); free(lp, M_LOMACFS); if (error) { *vpp = NULL; return (error); } else return (EEXIST); } } error = getnewvnode(VT_NULL, mp, lomacfs_vnodeop_p, vpp); if (error) { vput(lowervp); free(lp, M_LOMACFS); return (error); } vp = *vpp; vp->v_type = lowervp != NULL ? lowervp->v_type : VBAD; if (vp->v_type == VCHR) vp->v_rdev = lowervp->v_rdev; vp->v_data = lp; lp->ln_vp = vp; lp->ln_lowervp = lowervp; if (lowervp != NULL) vhold(lowervp); get_subject_lattr(curthread->td_proc, &subjlattr); lp->ln_flags = 0; lomac_plm_init_lomacfs_vnode(dvp, vp, cnp, &subjlattr); /* retrieve the just-initialized attributes */ lobj.lo_type = LO_TYPE_LVNODE; lobj.lo_object.vnode = vp; get_object_lattr(&lobj, &objlattr); /* propogate the lattr to the underlying vnode */ lobj.lo_type = LO_TYPE_UVNODE; lobj.lo_object.vnode = lowervp; set_object_lattr(&lobj, objlattr); #if defined(LOMAC_DEBUG_INCNAME) if (cnp == NULL) strncpy(lp->ln_name, "/", sizeof(lp->ln_name)); else { strncpy(lp->ln_name, cnp->cn_nameptr, cnp->cn_namelen); lp->ln_name[cnp->cn_namelen] = '\0'; } #endif error = vn_lock(vp, LK_EXCLUSIVE | LK_RETRY | LK_THISLAYER, td); if (error) panic("lomacfs_node_alloc: can't lock new vnode\n"); if (cnp == NULL) vp->v_flag |= VROOT; else if (cnp->cn_flags & MAKEENTRY) cache_enter(dvp, vp, cnp); #if defined(LOMAC_DEBUG_NODE_ALLOC) printf("lomacfs: made vp %p for lvp %p \"%.*s\" in dvp %p from %s\n", vp, lowervp, cnp ? (int)cnp->cn_namelen : 0, cnp ? cnp->cn_nameptr : "", dvp, lowervp != NULL ? lowervp->v_mount->mnt_stat.f_mntonname : ""); #endif return (0); } diff --git a/sys/security/lomac/lomacfs_vfsops.c b/sys/security/lomac/lomacfs_vfsops.c index c7ee93afc5b5..95b99e8a0fe7 100644 --- a/sys/security/lomac/lomacfs_vfsops.c +++ b/sys/security/lomac/lomacfs_vfsops.c @@ -1,199 +1,199 @@ /*- - * Copyright (c) 2001 Networks Associates Technologies, Inc. + * Copyright (c) 2001 Networks Associates Technology, Inc. * All rights reserved. * * This software was developed for the FreeBSD Project by NAI Labs, the * Security Research Division of Network Associates, Inc. under * DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA * CHATS research program. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $Id$ * $FreeBSD$ */ #include #include #include #include #include #include #include #include #include #include #include "lomacfs.h" #include "kernel_mediate.h" MALLOC_DEFINE(M_LOMACFS, "LOMACFS", "LOMAC filesystem objects"); static int lomacfs_mount(struct mount *mp, char *path, caddr_t data, struct nameidata *ndp, struct thread *td); static int lomacfs_statfs(struct mount *mp, struct statfs *sbp, struct thread *td); static int lomacfs_unmount(struct mount *mp, int mntflags, struct thread *td); static int lomacfs_mount(struct mount *mp, char *path, caddr_t data, struct nameidata *ndp, struct thread *td) { if (mp->mnt_flag & MNT_UPDATE || VISLOMAC(mp->mnt_vnodecovered)) return (EOPNOTSUPP); mp->mnt_flag |= MNT_LOCAL; mp->mnt_flag &= ~MNT_RDONLY; mp->mnt_data = malloc(sizeof(struct lomac_mount), M_LOMACFS, M_WAITOK | M_ZERO); vfs_getnewfsid(mp); strncpy(mp->mnt_stat.f_mntfromname, "lomacfs", MNAMELEN); (void)lomacfs_statfs(mp, &mp->mnt_stat, td); /* * Keep around an extra ref for dounmount() to vrele() after the * VFS_UNMOUNT()... (who knows...) */ vref(mp->mnt_vnodecovered); if (VOP_ISLOCKED(mp->mnt_vnodecovered, NULL)) VOP_UNLOCK(mp->mnt_vnodecovered, 0, td); return (0); } static int lomacfs_statfs(struct mount *mp, struct statfs *sbp, struct thread *td) { struct statfs tmpstat; int error; bzero(&tmpstat, sizeof(tmpstat)); error = VFS_STATFS(mp->mnt_vnodecovered->v_mount, &tmpstat, td); if (error) return (error); sbp->f_type = tmpstat.f_type; sbp->f_flags = tmpstat.f_flags; sbp->f_bsize = tmpstat.f_bsize; sbp->f_iosize = tmpstat.f_iosize; sbp->f_blocks = tmpstat.f_blocks; sbp->f_bfree = tmpstat.f_bfree; sbp->f_bavail = tmpstat.f_bavail; sbp->f_files = tmpstat.f_files; sbp->f_ffree = tmpstat.f_ffree; if (sbp != &mp->mnt_stat) { bcopy(&mp->mnt_stat.f_fsid, &sbp->f_fsid, sizeof(sbp->f_fsid)); bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN); bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN); } return (0); } static int lomacfs_unmount(struct mount *mp, int mntflags, struct thread *td) { struct vnode *crootvp = VFSTOLOMAC(mp)->lm_rootvp; int error; int flags = 0; if (mntflags & MNT_FORCE) flags |= FORCECLOSE; if (VFSTOLOMAC(mp)->lm_flags & LM_TOOKROOT) { mtx_lock(&crootvp->v_interlock); crootvp->v_flag |= VROOT; mtx_unlock(&crootvp->v_interlock); } error = vflush(mp, 1, flags); /* have an extra root ref */ if (error) return (error); free(VFSTOLOMAC(mp), M_LOMACFS); /* bye, lomacfs. */ return (0); } static int lomacfs_root(struct mount *mp, struct vnode **vpp) { int error; if (VFSTOLOMAC(mp)->lm_rootvp == NULL) { struct vnode *rootvp, *crootvp; crootvp = mp->mnt_vnodecovered; error = lomacfs_node_alloc(mp, NULL, NULL, crootvp, &rootvp); if (error) return (error); /* * Reference twice to match the rest of the lomacfs vnodes. */ vref(crootvp); vref(crootvp); VFSTOLOMAC(mp)->lm_rootvp = rootvp; /* * This releases the lock on root, but it doesn't release * the reference so that root won't "disappear" until * unmount. */ error = VOP_UNLOCK(rootvp, 0, curthread); if (error) return (error); /* * This is some strange magic here... I need to pretend * that the mounted-on directory isn't a root vnode if I * want things like __getcwd() to just fail and not crash. */ mtx_lock(&crootvp->v_interlock); if (crootvp->v_flag & VROOT && crootvp == rootvnode) { crootvp->v_flag &= ~VROOT; VFSTOLOMAC(mp)->lm_flags |= LM_TOOKROOT; } mtx_unlock(&crootvp->v_interlock); } *vpp = VFSTOLOMAC(mp)->lm_rootvp; return (vget(*vpp, LK_EXCLUSIVE, curthread)); } static struct vfsops lomacfs_vfsops = { lomacfs_mount, vfs_stdstart, lomacfs_unmount, lomacfs_root, vfs_stdquotactl, lomacfs_statfs, vfs_stdsync, vfs_stdvget, vfs_stdfhtovp, vfs_stdcheckexp, vfs_stdvptofh, vfs_stdinit, vfs_stduninit, vfs_stdextattrctl }; VFS_SET(lomacfs_vfsops, lomacfs, VFCF_LOOPBACK); MODULE_VERSION(lomacfs, 1); MODULE_DEPEND(lomacfs, lomac_plm, 1, 1, 1); diff --git a/sys/security/lomac/lomacfs_vnops.c b/sys/security/lomac/lomacfs_vnops.c index fb1c3f476eba..430da86eddb2 100644 --- a/sys/security/lomac/lomacfs_vnops.c +++ b/sys/security/lomac/lomacfs_vnops.c @@ -1,1151 +1,1151 @@ /*- - * Copyright (c) 2001 Networks Associates Technologies, Inc. + * Copyright (c) 2001 Networks Associates Technology, Inc. * All rights reserved. * * This software was developed for the FreeBSD Project by NAI Labs, the * Security Research Division of Network Associates, Inc. under * DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA * CHATS research program. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $Id$ * $FreeBSD$ */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "lomacfs.h" #include "kernel_mediate.h" #include "kernel_monitor.h" #if defined(LOMAC_DEBUG_LOOKUPSTATS) static unsigned int lomacfs_successful_lookups, lomacfs_failed_lookups, lomacfs_successful_cachedlookups, lomacfs_failed_cachedlookups, lomacfs_node_alloc_clashes, lomacfs_node_alloc_failures; SYSCTL_NODE(_vfs, OID_AUTO, lomacfs, CTLFLAG_RW, 0, "LOMACFS filesystem"); SYSCTL_NODE(_vfs_lomacfs, OID_AUTO, debug, CTLFLAG_RW, 0, "debug stats"); SYSCTL_UINT(_vfs_lomacfs_debug, OID_AUTO, successful_lookups, CTLFLAG_RW, &lomacfs_successful_lookups, 0, ""); SYSCTL_UINT(_vfs_lomacfs_debug, OID_AUTO, failed_lookups, CTLFLAG_RW, &lomacfs_failed_lookups, 0, ""); SYSCTL_UINT(_vfs_lomacfs_debug, OID_AUTO, successful_cachedlookups, CTLFLAG_RW, &lomacfs_successful_cachedlookups, 0, ""); SYSCTL_UINT(_vfs_lomacfs_debug, OID_AUTO, failed_cachedlookups, CTLFLAG_RW, &lomacfs_failed_cachedlookups, 0, ""); SYSCTL_UINT(_vfs_lomacfs_debug, OID_AUTO, node_alloc_clashes, CTLFLAG_RW, &lomacfs_node_alloc_clashes, 0, ""); SYSCTL_UINT(_vfs_lomacfs_debug, OID_AUTO, node_alloc_failures, CTLFLAG_RW, &lomacfs_node_alloc_failures, 0, ""); #endif static int lomacfs_defaultop( struct vop_generic_args /* { struct vnodeop_desc *a_desc; } */ *ap ) { printf("lomacfs: %s unsupported\n", ap->a_desc->vdesc_name); return (EOPNOTSUPP); } static int lomacfs_inactive( struct vop_inactive_args /* { struct vnode *a_vp; struct thread *a_td; } */ *ap ) { struct vnode *vp = ap->a_vp; struct vnode *lvp = VTOLVP(vp); struct thread *td = ap->a_td; KASSERT(lvp != NULL, ("inactive with NULL lowervp")); VOP_UNLOCK(ap->a_vp, 0, td); /* * Temporarily drop our reference to the lower vnode, while keeping * it held, to possibly call VOP_INACTIVE() on the lower layer. */ vrele(lvp); #if defined(LOMAC_DEBUG_INACTIVE) do { #if defined(LOMAC_DEBUG_INCNAME) const char *name = VTOLOMAC(vp)->ln_name; #else const char *name = "[unknown]"; #endif printf("lomacfs: inactive(%p \"%s\"), lvp usecount down to %u\n", vp, name, lvp->v_usecount); } while (0); #endif /* * Since the lower fs may actually remove the vnode on last * release, destroy ourselves mostly here if that occurs. * * Additionally, devices should be totally freed * on last close, not lazily. */ if (lvp->v_usecount == 0 && (lvp->v_type != VREG && lvp->v_type != VDIR)) { vdrop(lvp); VTOLVP(vp) = NULL; cache_purge(vp); } else vref(lvp); return (0); } static int lomacfs_reclaim( struct vop_reclaim_args /* { struct vnode *a_vp; struct thread *a_td; } */ *ap ) { struct vnode *vp = ap->a_vp; struct lomac_node *ln = VTOLOMAC(vp); struct vnode *lvp = VTOLVP(vp); if (lvp != NULL) vrele(lvp); #if defined(LOMAC_DEBUG_RECLAIM) if (lvp != NULL) { #if defined(LOMAC_DEBUG_INCNAME) const char *name = ln->ln_name; #else const char *name = "[unknown]"; #endif printf("lomacfs: reclaim(%p \"%s\"), lvp usecount down to %u\n", vp, name, lvp->v_usecount); } #endif if (lvp != NULL) vdrop(lvp); vp->v_data = NULL; vp->v_rdev = NULL; free(ln, M_LOMACFS); return (0); } static int lomacfs_print( struct vop_print_args /* { struct vnode *a_vp; } */ *ap ) { struct vnode *vp = ap->a_vp; printf ("\ttag VT_LOMACFS, vp=%p, lowervp=%p\n", vp, VTOLVP(vp)); return (0); } static int lomacfs_lock( struct vop_lock_args /* { struct vnode *a_vp; int a_flags; struct thread *a_td; } */ *ap ) { struct vnode *vp = ap->a_vp; int flags = ap->a_flags; struct thread *td = ap->a_td; struct vnode *lvp; int lflags = flags & ~(LK_INTERLOCK | LK_THISLAYER); int error; /* * To prevent race conditions involving doing a lookup * on "..", we have to lock the lower node, then lock our * node. Most of the time it won't matter that we lock our * node (as any locking would need the lower one locked * first). But we can LK_DRAIN the upper lock as a step * towards decomissioning it. */ lvp = VTOLVP(vp); if (lvp == NULL || flags & LK_THISLAYER) return (lockmgr(&vp->v_lock, flags, &vp->v_interlock, td)); if (flags & LK_INTERLOCK) { mtx_unlock(&vp->v_interlock); flags &= ~LK_INTERLOCK; } if ((flags & LK_TYPE_MASK) == LK_DRAIN) { error = vn_lock(lvp, (lflags & ~LK_TYPE_MASK) | LK_EXCLUSIVE | LK_CANRECURSE, td); } else error = vn_lock(lvp, lflags | LK_CANRECURSE, td); if (error) return (error); error = lockmgr(&vp->v_lock, flags, &vp->v_interlock, td); if (error) VOP_UNLOCK(lvp, 0, td); return (error); } /* * We need to process our own vnode unlock and then clear the * interlock flag as it applies only to our vnode, not the * vnodes below us on the stack. */ static int lomacfs_unlock( struct vop_unlock_args /* { struct vnode *a_vp; int a_flags; struct thread *a_td; } */ *ap ) { struct vnode *vp = ap->a_vp; int flags = ap->a_flags; int lflags = (ap->a_flags | LK_RELEASE) & ~(LK_THISLAYER | LK_INTERLOCK); struct thread *td = ap->a_td; struct vnode *lvp = VTOLVP(vp); int error; error = lockmgr(&vp->v_lock, flags | LK_RELEASE, &vp->v_interlock, td); if (lvp == NULL || flags & LK_THISLAYER || error) return (error); /* * Hmm... in a vput(), this means we'll grab the lomacfs interlock, * then the lower interlock. I don't think this matters, though, * since both won't be held at the same time. */ if (lvp != NULL) error = VOP_UNLOCK(lvp, lflags, td); return (error); } static int lomacfs_islocked( struct vop_islocked_args /* { struct vnode *a_vp; struct thread *a_td; } */ *ap ) { struct vnode *vp = ap->a_vp; struct thread *td = ap->a_td; return (lockstatus(&vp->v_lock, td)); } static int lomacfs_lookup( struct vop_lookup_args /* { struct vnode *a_dvp; struct vnode **a_vpp; struct componentname *a_cnp; } */ *ap ) { int error; error = vfs_cache_lookup(ap); #if defined(LOMAC_DEBUG_LOOKUPSTATS) if (error == 0) lomacfs_successful_lookups++; else lomacfs_failed_lookups++; #endif #if defined(LOMAC_DEBUG_LOOKUP) if (error == 0 && (*ap->a_vpp)->v_mount == dvp->v_mount) { struct vnode *vp = *ap->a_vpp; #if defined(LOMAC_DEBUG_INCNAME) const char *name = VTOLOMAC(vp)->ln_name; #else const char *name = "[unknown]"; #endif printf("lomacfs: lookup(%p \"%s\"), lvp usecount up to %u\n", vp, name, VTOLVP(vp)->v_usecount); } #endif return (error); } static int lomacfs_cachedlookup( struct vop_lookup_args /* { struct vnode *a_dvp; struct vnode **a_vpp; struct componentname *a_cnp; } */ *ap ) { struct vnode *dvp = ap->a_dvp; struct componentname *cnp = ap->a_cnp; struct vnode *ldvp = VTOLVP(dvp); struct vnode *lvp; int makeentry; int error; if (cnp->cn_flags & ISLASTCN && cnp->cn_nameiop != LOOKUP && cnp->cn_nameiop != CREATE) { lomac_object_t lobj = { LO_TYPE_LVNODE, { dvp } }; const char *op; if (cnp->cn_nameiop == DELETE) op = "delete"; else op = "rename"; if (!mediate_subject_object(op, curthread->td_proc, &lobj)) return (EPERM); } makeentry = cnp->cn_flags & MAKEENTRY; cnp->cn_flags &= ~makeentry; error = VOP_LOOKUP(ldvp, &lvp, cnp); cnp->cn_flags |= makeentry; if ((error == 0 || error == EJUSTRETURN) && cnp->cn_flags != (cnp->cn_flags | LOCKPARENT | ISLASTCN)) (void)VOP_UNLOCK(dvp, LK_THISLAYER, curthread); if (error == 0 && lvp->v_type != VSOCK) { struct mount *mp; /* * Check to see if the vnode has been mounted on; * if so find the root of the mounted file system. */ if (lvp->v_type == VDIR && (mp = lvp->v_mountedhere) && (cnp->cn_flags & NOCROSSMOUNT) == 0) { struct vnode *tdp; if (vfs_busy(mp, 0, 0, curthread)) goto forget_it; VOP_UNLOCK(lvp, 0, curthread); error = VFS_ROOT(mp, &tdp); vfs_unbusy(mp, curthread); if (error) { vrele(lvp); return (error); } vrele(lvp); lvp = tdp; } forget_it: /* * For a create or for devices (dynamic things, aren't they), * don't enter the vnode into the cache. */ if (cnp->cn_nameiop == CREATE || lvp->v_type == VCHR) cnp->cn_flags &= ~makeentry; /* * The top half of dvp is locked, but ldvp is unlocked. * Additionally, lvp is locked already, and * lomacfs_node_alloc() always returns it locked. */ error = lomacfs_node_alloc(dvp->v_mount, cnp, dvp, lvp, ap->a_vpp); if (cnp->cn_nameiop == CREATE) cnp->cn_flags |= makeentry; #if defined(LOMAC_DEBUG_LOOKUPSTATS) if (error) { if (error != EEXIST) { lomacfs_node_alloc_failures++; } else { lomacfs_node_alloc_clashes++; error = 0; } } #else if (error == EEXIST) error = 0; #endif } else if (error == 0) { /* * For sockets, just return the "real" thing * after entering it into the cache. */ *ap->a_vpp = lvp; if (cnp->cn_nameiop != CREATE && cnp->cn_flags & MAKEENTRY) cache_enter(dvp, lvp, cnp); } #if defined(LOMAC_DEBUG_LOOKUPSTATS) if (error == 0) lomacfs_successful_cachedlookups++; else lomacfs_failed_cachedlookups++; #endif return (error); } static int lomacfs_getattr( struct vop_getattr_args /* { struct vnode *a_vp; struct vattr *a_vap; struct ucred *a_cred; struct thread *a_td; */ *ap ) { struct vnode *vp = ap->a_vp; struct vattr *vap = ap->a_vap; int error; error = VOP_GETATTR(VTOLVP(vp), vap, ap->a_cred, ap->a_td); if (error == 0 && vap->va_fsid == VNOVAL) vap->va_fsid = VTOLVP(vp)->v_mount->mnt_stat.f_fsid.val[0]; return (error); } static int lomacfs_setattr( struct vop_getattr_args /* { struct vnode *a_vp; struct vattr *a_vap; struct ucred *a_cred; struct thread *a_td; */ *ap ) { lomac_object_t lobj = { LO_TYPE_LVNODE, { ap->a_vp } }; int error; if (mediate_subject_object(ap->a_desc->vdesc_name, curthread->td_proc, &lobj)) error = VOP_SETATTR(VTOLVP(ap->a_vp), ap->a_vap, ap->a_cred, ap->a_td); else error = EPERM; return (error); } static int lomacfs_readdir( struct vop_readdir_args /* { struct vnode *a_vp; struct uio *a_uio; struct ucred *a_cred; int *a_eofflag; int *a_ncookies; u_long **a_cookies; } */ *ap ) { return (VOP_READDIR(VTOLVP(ap->a_vp), ap->a_uio, ap->a_cred, ap->a_eofflag, ap->a_ncookies, ap->a_cookies)); } static int lomacfs_open( struct vop_open_args /* { struct vnode *a_vp; int a_mode; struct ucred *a_cred; struct thread *a_td; } */ *ap ) { lomac_object_t lobj; int error; lobj.lo_type = LO_TYPE_LVNODE; lobj.lo_object.vnode = ap->a_vp; if (!mediate_subject_object_open(ap->a_td->td_proc, &lobj)) error = EPERM; else error = VOP_OPEN(VTOLVP(ap->a_vp), ap->a_mode, ap->a_cred, ap->a_td); return (error); } static int lomacfs_close( struct vop_close_args /* { struct vnode *a_vp; int a_fflag; struct ucred *a_cred; struct thread *a_td; } */ *ap ) { struct vnode *vp = ap->a_vp; struct vnode *lvp = VTOLVP(vp); int error; /* * XXX * Try to cope with the horrible semantics introduced here... */ vref(lvp); error = VOP_CLOSE(lvp, ap->a_fflag, ap->a_cred, ap->a_td); if (error == EAGAIN) error = 0; else vrele(lvp); return (error); } static int lomacfs_access( struct vop_access_args /* { struct vnode *a_vp; int a_mode; struct ucred *a_cred; struct thread *a_td; } */ *ap ) { return (VOP_ACCESS(VTOLVP(ap->a_vp), ap->a_mode, ap->a_cred, ap->a_td)); } static int lomacfs_readlink( struct vop_readlink_args /* { struct vnode *a_vp; struct uio *a_uio; struct ucred *a_cred; } */ *ap ) { struct vnode *lvp = VTOLVP(ap->a_vp); if (lvp == NULL) return (EPERM); return (VOP_READLINK(lvp, ap->a_uio, ap->a_cred)); } static int lomacfs_lease( struct vop_lease_args /* { struct vnode *a_vp; struct thread *a_td; struct ucred *a_cred; int a_flag; } */ *ap ) { struct vnode *lvp = VTOLVP(ap->a_vp); return (VOP_LEASE(lvp, ap->a_td, ap->a_cred, ap->a_flag)); } static int lomacfs_read( struct vop_read_args /* { struct vnode *a_vp; struct uio *a_uio; int a_ioflag; struct ucred *a_cred; } */ *ap ) { struct vnode *lvp = VTOLVP(ap->a_vp); lomac_object_t lobj = { LO_TYPE_LVNODE, { ap->a_vp } }; int error; error = monitor_read_object(curthread->td_proc, &lobj); if (error == 0) error = VOP_READ(lvp, ap->a_uio, ap->a_ioflag, ap->a_cred); return (error); } static int lomacfs_write( struct vop_write_args /* { struct vnode *a_vp; struct uio *a_uio; int a_ioflag; struct ucred *a_cred; } */ *ap ) { struct vnode *lvp = VTOLVP(ap->a_vp); lomac_object_t lobj = { LO_TYPE_LVNODE, { ap->a_vp } }; int error; if (mediate_subject_object(ap->a_desc->vdesc_name, curthread->td_proc, &lobj)) error = VOP_WRITE(lvp, ap->a_uio, ap->a_ioflag, ap->a_cred); else error = EIO; return (error); } static int lomacfs_ioctl( struct vop_ioctl_args /* { struct vnode *a_vp; u_long a_command; caddr_t a_data; int a_fflag; struct ucred *a_cred; struct thread *a_td; } */ *ap ) { struct vnode *lvp = VTOLVP(ap->a_vp); return (VOP_IOCTL(lvp, ap->a_command, ap->a_data, ap->a_fflag, ap->a_cred, ap->a_td)); } static int lomacfs_muxcreate( struct vop_create_args /* { struct vnode *a_dvp; struct vnode **a_vpp; struct componentname *a_cnp; struct vattr *a_vap; } */ *ap ) { struct vnode *dvp = ap->a_dvp; struct vnode *ldvp = VTOLVP(dvp); struct componentname *cnp = ap->a_cnp; struct vattr *vap = ap->a_vap; int makeentry = cnp->cn_flags & MAKEENTRY; lomac_object_t lobj = { LO_TYPE_LVNODE, { dvp } }; struct thread *td = curthread; int error; if (!mediate_subject_object(ap->a_desc->vdesc_name, td->td_proc, &lobj) || (vap->va_type == VCHR && !mediate_subject_at_level("mknod", curthread->td_proc, LOMAC_HIGHEST_LEVEL))) return (EPERM); ap->a_dvp = ldvp; cnp->cn_flags &= ~makeentry; error = VCALL(ldvp, ap->a_desc->vdesc_offset, ap); if (error == 0) { struct vnode *vp; int issock; issock = vap->va_type == VSOCK; vp = *ap->a_vpp; *ap->a_vpp = NULL; if (!issock) cnp->cn_flags |= makeentry; error = lomacfs_node_alloc(dvp->v_mount, cnp, dvp, vp, ap->a_vpp); if (error) vput(vp); else if (issock) { /* * I should really find a nicer way to do this. */ vref(vp); vput(*ap->a_vpp); *ap->a_vpp = vp; (void)VOP_LOCK(vp, LK_EXCLUSIVE | LK_RETRY, td); } } return (error); } static int lomacfs_muxremove( struct vop_remove_args /* { struct vnode *a_dvp; struct vnode *a_vp; struct componentname *a_cnp; } */ *ap ) { struct vnode *dvp = ap->a_dvp; struct vnode *vp = ap->a_vp; int error; ap->a_dvp = VTOLVP(dvp); if (VISLOMAC(vp)) ap->a_vp = VTOLVP(vp); error = VCALL(ap->a_dvp, ap->a_desc->vdesc_offset, ap); if (error == 0) cache_purge(vp); return (error); } static int lomacfs_fsync( struct vop_fsync_args /* { struct vnode *a_vp; struct ucred *a_cred; int a_waitfor; struct thread *a_td; } */ *ap ) { return (VOP_FSYNC(VTOLVP(ap->a_vp), ap->a_cred, ap->a_waitfor, ap->a_td)); } static int lomacfs_advlock( struct vop_advlock_args /* { struct vnode *a_vp; caddr_t a_id; int a_op; struct flock *a_fl; int a_flags; } */ *ap ) { return (VOP_ADVLOCK(VTOLVP(ap->a_vp), ap->a_id, ap->a_op, ap->a_fl, ap->a_flags)); } static int lomacfs_whiteout( struct vop_whiteout_args /* { struct vnode *a_dvp; struct componentname *a_cnp; int a_flags; } */ *ap ) { return (VOP_WHITEOUT(VTOLVP(ap->a_dvp), ap->a_cnp, ap->a_flags)); } static int lomacfs_poll( struct vop_poll_args /* { struct vnode *a_vp; int a_events; struct ucred *a_cred; struct thread *a_td; } */ *ap ) { return (VOP_POLL(VTOLVP(ap->a_vp), ap->a_events, ap->a_cred, ap->a_td)); } static int lomacfs_revoke( struct vop_revoke_args /* { struct vnode *a_vp; int a_flags; } */ *ap ) { return (VOP_REVOKE(VTOLVP(ap->a_vp), ap->a_flags)); } static int lomacfs_link( struct vop_link_args /* { struct vnode *a_tdvp; struct vnode *a_vp; struct componentname *a_cnp; } */ *ap ) { struct vnode *tdvp = ap->a_tdvp; struct vnode *vp = ap->a_vp; struct vnode *lvp = VISLOMAC(vp) ? VTOLVP(vp) : vp; struct componentname *cnp = ap->a_cnp; int error; error = VOP_LINK(VTOLVP(tdvp), lvp, cnp); if (error == 0 && vp->v_type == VSOCK) { cache_enter(tdvp, vp, cnp); #if defined(LOMAC_DEBUG_LINK) do { struct vnode *nvp; int nerror; nerror = cache_lookup(tdvp, &nvp, cnp); printf("lomacfs: link(%p), cache_lookup() = %d (%p)\n", vp, nerror, nvp); } while (0); #endif } return (error); } static int lomacfs_rename( struct vop_rename_args /* { struct vnode *a_fdvp; struct vnode *a_fvp; struct componentname *a_fcnp; struct vnode *a_tdvp; struct vnode *a_tvp; struct componentname *a_tcnp; } */ *ap ) { struct vnode *fdvp = ap->a_fdvp; struct vnode *fvp = ap->a_fvp; struct componentname *fcnp = ap->a_fcnp; struct vnode *tdvp = ap->a_tdvp; struct vnode *tvp = ap->a_tvp; struct componentname *tcnp = ap->a_tcnp; int fvp_is_lomac = VISLOMAC(fvp); int error; vref(VTOLVP(fdvp)); /* * Handle the case when LOMAC returns a real vnode for * VSOCK, rather than the LOMAC covering vnode. */ if (fvp_is_lomac) vref(VTOLVP(fvp)); vref(VTOLVP(tdvp)); if (tvp != NULL) vref(VTOLVP(tvp)); error = VOP_RENAME(VTOLVP(fdvp), fvp_is_lomac ? VTOLVP(fvp) : fvp, fcnp, VTOLVP(tdvp), tvp != NULL ? VTOLVP(tvp) : NULL, tcnp); if (fvp->v_type == VDIR) { if (tvp != NULL && tvp->v_type == VDIR) cache_purge(tdvp); cache_purge(fdvp); } cache_purge(fvp); if (tvp != NULL) cache_purge(tvp); (void)VOP_UNLOCK(tdvp, LK_THISLAYER, curthread); vrele(fdvp); if (fvp_is_lomac) vrele(fvp); vrele(tdvp); if (tvp != NULL) { (void)VOP_UNLOCK(tvp, LK_THISLAYER, curthread); vrele(tvp); } else if (tcnp->cn_nameiop == RENAME /* NOCACHE unsets MAKEENTRY */ && fvp->v_type == VSOCK) cache_enter(tdvp, fvp, tcnp); return (error); } static int lomacfs_strategy( struct vop_strategy_args /* { struct vnode *a_vp; struct buf *a_bp; } */ *ap ) { return (VOP_STRATEGY(VTOLVP(ap->a_vp), ap->a_bp)); } /* * Let an underlying filesystem do the work of creating the "actual" * vm_object_t, and we will reference it. */ static int lomacfs_createvobject( struct vop_createvobject_args /* { struct vnode *vp; struct ucred *cred; struct proc *p; } */ *ap ) { struct vnode *vp = ap->a_vp; struct vnode *lowervp = VTOLOMAC(vp) != NULL ? VTOLVP(vp) : NULL; int error; if (vp->v_type == VNON || lowervp == NULL) return (EINVAL); error = VOP_CREATEVOBJECT(lowervp, ap->a_cred, ap->a_td); if (error) return (error); vp->v_flag |= VOBJBUF; return (error); } /* * We need to destroy the lower vnode object only if we created it. * XXX - I am very unsure about all of this. */ static int lomacfs_destroyvobject( struct vop_destroyvobject_args /* { struct vnode *vp; } */ *ap ) { struct vnode *vp = ap->a_vp; vp->v_flag &= ~VOBJBUF; return (0); } static int lomacfs_bmap( struct vop_bmap_args /* { struct vnode *a_vp; daddr_t a_bn; struct vnode **a_vpp; daddr_t *a_bnp; int *a_runp; int *a_runb; } */ *ap ) { return (VOP_BMAP(VTOLVP(ap->a_vp), ap->a_bn, ap->a_vpp, ap->a_bnp, ap->a_runp, ap->a_runb)); } static int lomacfs_getpages( struct vop_getpages_args /* { struct vnode *a_vp; vm_page_t *a_m; int a_count; int a_reqpage; vm_ooffset_t a_offset; } */ *ap ) { return (VOP_GETPAGES(VTOLVP(ap->a_vp), ap->a_m, ap->a_count, ap->a_reqpage, ap->a_offset)); } static int lomacfs_putpages( struct vop_putpages_args /* { struct vnode *a_vp; vm_page_t *a_m; int a_count; int a_sync; int *a_rtvals; vm_ooffset_t a_offset; } */ *ap ) { return (VOP_PUTPAGES(VTOLVP(ap->a_vp), ap->a_m, ap->a_count, ap->a_sync, ap->a_rtvals, ap->a_offset)); } static int lomacfs_getvobject( struct vop_getvobject_args /* { struct vnode *a_vp; struct vm_object **a_objpp; } */ *ap ) { struct vnode *lvp = VTOLVP(ap->a_vp); if (lvp == NULL) return EINVAL; return (VOP_GETVOBJECT(lvp, ap->a_objpp)); } static int lomacfs_kqfilter( struct vop_kqfilter_args /* { struct vnode *a_vp; struct knote *a_kn; } */ *ap ) { return (VOP_KQFILTER(VTOLVP(ap->a_vp), ap->a_kn)); } static int lomacfs_pathconf( struct vop_pathconf_args /* { struct vnode *a_vp; int a_name; register_t *a_retval; } */ *ap ) { return (VOP_PATHCONF(VTOLVP(ap->a_vp), ap->a_name, ap->a_retval)); } static int lomacfs_reallocblks( struct vop_reallocblks_args /* { struct vnode *a_vp; struct cluster_save *a_buflist; } */ *ap ) { return (VOP_REALLOCBLKS(VTOLVP(ap->a_vp), ap->a_buflist)); } static int lomacfs_freeblks( struct vop_freeblks_args /* { struct vnode *a_vp; daddr_t a_addr; daddr_t a_length; } */ *ap ) { return (VOP_FREEBLKS(VTOLVP(ap->a_vp), ap->a_addr, ap->a_length)); } static int lomacfs_getacl( struct vop_getacl_args /* { struct vnode *a_vp; acl_type_t a_type; struct acl *a_aclp; struct ucred *a_cred; struct thread *a_td; } */ *ap ) { return (VOP_GETACL(VTOLVP(ap->a_vp), ap->a_type, ap->a_aclp, ap->a_cred, ap->a_td)); } static int lomacfs_setacl( struct vop_setacl_args /* { struct vnode *a_vp; acl_type_t a_type; struct acl *a_aclp; struct ucred *a_cred; struct thread *a_td; } */ *ap ) { lomac_object_t lobj; lobj.lo_type = LO_TYPE_LVNODE; lobj.lo_object.vnode = ap->a_vp; if (!mediate_subject_object("setacl", ap->a_td->td_proc, &lobj)) return (EPERM); else return (VOP_SETACL(VTOLVP(ap->a_vp), ap->a_type, ap->a_aclp, ap->a_cred, ap->a_td)); } static int lomacfs_aclcheck( struct vop_aclcheck_args /* { struct vnode *a_vp; acl_type_t a_type; struct acl *a_aclp; struct ucred *a_cred; struct thread *a_td; } */ *ap ) { return (VOP_ACLCHECK(VTOLVP(ap->a_vp), ap->a_type, ap->a_aclp, ap->a_cred, ap->a_td)); } static int lomacfs_getextattr( struct vop_getextattr_args /* { struct vnode *a_vp; int a_attrnamespace; const char *a_name; struct uio *a_uio; size_t *a_size; struct ucred *a_cred; struct thread *a_td; } */ *ap ) { lomac_object_t lobj; lobj.lo_type = LO_TYPE_LVNODE; lobj.lo_object.vnode = ap->a_vp; if (monitor_read_object(ap->a_td->td_proc, &lobj)) return (EPERM); else return (VOP_GETEXTATTR(VTOLVP(ap->a_vp), ap->a_attrnamespace, ap->a_name, ap->a_uio, ap->a_size, ap->a_cred, ap->a_td)); } static int lomacfs_setextattr( struct vop_setextattr_args /* { struct vnode *a_vp; int a_attrnamespace; const char *a_name; struct uio *a_uio; struct ucred *a_cred; struct thread *a_td; } */ *ap ) { lomac_object_t lobj; lobj.lo_type = LO_TYPE_LVNODE; lobj.lo_object.vnode = ap->a_vp; if (!mediate_subject_object("setextattr", ap->a_td->td_proc, &lobj)) return (EPERM); else return (VOP_SETEXTATTR(VTOLVP(ap->a_vp), ap->a_attrnamespace, ap->a_name, ap->a_uio, ap->a_cred, ap->a_td)); } vop_t **lomacfs_vnodeop_p; static struct vnodeopv_entry_desc lomacfs_vnodeop_entries[] = { { &vop_default_desc, (vop_t *)lomacfs_defaultop }, { &vop_inactive_desc, (vop_t *)lomacfs_inactive }, { &vop_reclaim_desc, (vop_t *)lomacfs_reclaim }, { &vop_print_desc, (vop_t *)lomacfs_print }, { &vop_lock_desc, (vop_t *)lomacfs_lock }, { &vop_unlock_desc, (vop_t *)lomacfs_unlock }, { &vop_islocked_desc, (vop_t *)lomacfs_islocked }, { &vop_lookup_desc, (vop_t *)lomacfs_lookup }, { &vop_setattr_desc, (vop_t *)lomacfs_setattr }, { &vop_getattr_desc, (vop_t *)lomacfs_getattr }, { &vop_readdir_desc, (vop_t *)lomacfs_readdir }, { &vop_open_desc, (vop_t *)lomacfs_open }, { &vop_close_desc, (vop_t *)lomacfs_close }, { &vop_access_desc, (vop_t *)lomacfs_access }, { &vop_readlink_desc, (vop_t *)lomacfs_readlink }, { &vop_lease_desc, (vop_t *)lomacfs_lease }, { &vop_read_desc, (vop_t *)lomacfs_read }, { &vop_write_desc, (vop_t *)lomacfs_write }, { &vop_ioctl_desc, (vop_t *)lomacfs_ioctl }, { &vop_create_desc, (vop_t *)lomacfs_muxcreate }, { &vop_mkdir_desc, (vop_t *)lomacfs_muxcreate }, { &vop_mknod_desc, (vop_t *)lomacfs_muxcreate }, { &vop_symlink_desc, (vop_t *)lomacfs_muxcreate }, { &vop_remove_desc, (vop_t *)lomacfs_muxremove }, { &vop_rmdir_desc, (vop_t *)lomacfs_muxremove }, { &vop_fsync_desc, (vop_t *)lomacfs_fsync }, { &vop_advlock_desc, (vop_t *)lomacfs_advlock }, { &vop_whiteout_desc, (vop_t *)lomacfs_whiteout }, { &vop_poll_desc, (vop_t *)lomacfs_poll }, { &vop_link_desc, (vop_t *)lomacfs_link }, { &vop_rename_desc, (vop_t *)lomacfs_rename }, { &vop_revoke_desc, (vop_t *)lomacfs_revoke }, { &vop_cachedlookup_desc, (vop_t *)lomacfs_cachedlookup }, { &vop_lookup_desc, (vop_t *)lomacfs_lookup }, { &vop_bmap_desc, (vop_t *)lomacfs_bmap }, { &vop_getpages_desc, (vop_t *)lomacfs_getpages }, { &vop_putpages_desc, (vop_t *)lomacfs_putpages }, { &vop_strategy_desc, (vop_t *)lomacfs_strategy }, { &vop_createvobject_desc, (vop_t *)lomacfs_createvobject }, { &vop_destroyvobject_desc, (vop_t *)lomacfs_destroyvobject }, { &vop_getvobject_desc, (vop_t *)lomacfs_getvobject }, { &vop_getwritemount_desc, (vop_t *)vop_stdgetwritemount }, { &vop_kqfilter_desc, (vop_t *)lomacfs_kqfilter }, { &vop_pathconf_desc, (vop_t *)lomacfs_pathconf }, { &vop_reallocblks_desc, (vop_t *)lomacfs_reallocblks }, { &vop_freeblks_desc, (vop_t *)lomacfs_freeblks }, { &vop_getacl_desc, (vop_t *)lomacfs_getacl }, { &vop_setacl_desc, (vop_t *)lomacfs_setacl }, { &vop_aclcheck_desc, (vop_t *)lomacfs_aclcheck }, { &vop_getextattr_desc, (vop_t *)lomacfs_getextattr }, { &vop_setextattr_desc, (vop_t *)lomacfs_setextattr }, { NULL, NULL } }; static struct vnodeopv_desc lomacfs_vnodeopv_opv_desc = { &lomacfs_vnodeop_p, lomacfs_vnodeop_entries }; VNODEOP_SET(lomacfs_vnodeopv_opv_desc); diff --git a/sys/security/lomac/lomacio.h b/sys/security/lomac/lomacio.h index 33328e990b77..adce6191d0ca 100644 --- a/sys/security/lomac/lomacio.h +++ b/sys/security/lomac/lomacio.h @@ -1,59 +1,59 @@ /*- - * Copyright (c) 2001 Networks Associates Technologies, Inc. + * Copyright (c) 2001 Networks Associates Technology, Inc. * All rights reserved. * * This software was developed for the FreeBSD Project by NAI Labs, the * Security Research Division of Network Associates, Inc. under * DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA * CHATS research program. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $Id$ * $FreeBSD$ */ #ifndef LOMACIO_H #define LOMACIO_H #include #include struct lomac_fioctl { char path[MAXPATHLEN]; int level; /* LOMAC security level */ }; struct lomac_fioctl2 { char path[MAXPATHLEN]; int level; /* LOMAC security level */ int flags; }; #define LIOGETPLEVEL _IOWR('L', 0, int) /* get process level */ #define LIOGETFLEVEL _IOWR('L', 1, struct lomac_fioctl) /* get file level */ #define LIOGETFLATTR _IOWR('L', 3, struct lomac_fioctl2) /* get file level */ #define LIOPMAKELOWLEVEL _IO('L', 2) /* lower proc's level */ #endif /* LOMACIO_H */ diff --git a/sys/security/lomac/policy_plm.h b/sys/security/lomac/policy_plm.h index 533d4c3f03a6..5a2142ff9b1f 100644 --- a/sys/security/lomac/policy_plm.h +++ b/sys/security/lomac/policy_plm.h @@ -1,119 +1,119 @@ /*- - * Copyright (c) 2001 Networks Associates Technologies, Inc. + * Copyright (c) 2001 Networks Associates Technology, Inc. * All rights reserved. * * This software was developed for the FreeBSD Project by NAI Labs, the * Security Research Division of Network Associates, Inc. under * DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA * CHATS research program. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $Id$ * $FreeBSD$ */ #ifndef LOMAC_PLM_H #define LOMAC_PLM_H enum plm_level { LOW, SUBJ, HIGH }; enum plm_flags { PLM_NOFLAGS, /* rule applies to this node and its children */ PLM_CHILDOF /* rule applies to node's children, not the node */ }; #define LOWWRITE LN_ATTR_LOWWRITE #define LOWNOOPEN LN_ATTR_LOWNOOPEN #define NONETDEMOTE LN_ATTR_NONETDEMOTE #define NODEMOTE LN_ATTR_NODEMOTE static u_int plm_levelflags_to_node_flags[3][2] = { { LN_LOWEST_LEVEL, LN_INHERIT_LOW }, { LN_SUBJ_LEVEL, LN_INHERIT_SUBJ }, { LN_HIGHEST_LEVEL, LN_INHERIT_HIGH } }; typedef struct plm_rule { enum plm_level level; /* LOMAC level */ enum plm_flags flags; /* flags for PLM evaluation */ unsigned int attr; /* LN_ATTR_MASK of flags */ const char *path; /* absolute path for this PLM rule */ } plm_rule_t; /* The `plm' array maps levels onto all of the files in the filesystem */ static plm_rule_t plm[] = { { HIGH, PLM_NOFLAGS, 0, "/" }, /* everything initially inherits high level */ { HIGH, PLM_CHILDOF, 0, "/" }, { HIGH, PLM_NOFLAGS, NONETDEMOTE, "/sbin/dhclient" }, { HIGH, PLM_CHILDOF, 0, "/var" }, { HIGH, PLM_CHILDOF, LOWWRITE, "/dev" }, { HIGH, PLM_NOFLAGS, LOWNOOPEN, "/dev/mdctl" }, { HIGH, PLM_NOFLAGS, LOWNOOPEN, "/dev/pci" }, { HIGH, PLM_NOFLAGS, LOWNOOPEN, "/dev/kmem" }, { HIGH, PLM_NOFLAGS, LOWNOOPEN, "/dev/mem" }, { HIGH, PLM_NOFLAGS, LOWNOOPEN, "/dev/io" }, { HIGH, PLM_CHILDOF, 0, "/etc" }, { HIGH, PLM_NOFLAGS, LOWWRITE, "/tmp" }, { SUBJ, PLM_CHILDOF, 0, "/tmp" }, { HIGH, PLM_NOFLAGS, 0, "/tmp/.X11-unix" }, { HIGH, PLM_CHILDOF, LOWWRITE, "/tmp/.X11-unix" }, { SUBJ, PLM_CHILDOF, 0, "/proc" }, { LOW, PLM_CHILDOF, 0, "/mnt" }, /* all nfs mounts are low */ { LOW, PLM_CHILDOF, 0, "/home" }, { HIGH, PLM_NOFLAGS, NONETDEMOTE, "/usr/bin/env-nonetdemote" }, { HIGH, PLM_NOFLAGS, NODEMOTE, "/usr/bin/env-nodemote" }, { LOW, PLM_CHILDOF, 0, "/usr/home" }, { LOW, PLM_CHILDOF, 0, "/var/lib" }, { HIGH, PLM_NOFLAGS, LOWWRITE, "/var/tmp" }, { SUBJ, PLM_CHILDOF, 0, "/var/tmp" }, { LOW, PLM_NOFLAGS, 0, "/var/tmp/vi.recover" }, { SUBJ, PLM_CHILDOF, 0, "/var/tmp/vi.recover" }, { HIGH, PLM_NOFLAGS, LOWWRITE, "/usr/tmp" }, { SUBJ, PLM_CHILDOF, 0, "/usr/tmp" }, { HIGH, PLM_NOFLAGS, 0, "/usr/tmp/.X11-unix" }, { HIGH, PLM_CHILDOF, LOWWRITE, "/usr/tmp/.X11-unix" }, { LOW, PLM_NOFLAGS, 0, "/var/mail" }, { LOW, PLM_CHILDOF, 0, "/var/mail" }, { LOW, PLM_NOFLAGS, 0, "/var/spool/mqueue" }, { LOW, PLM_CHILDOF, 0, "/var/spool/mqueue" }, { LOW, PLM_NOFLAGS, 0, "/dev/log" }, { HIGH, PLM_NOFLAGS, 0, "/home/ftp" }, { HIGH, PLM_NOFLAGS, 0, "/usr/home/ftp" }, { HIGH, PLM_NOFLAGS, 0, "/mnt/cdrom" }, /* cdrom is high */ { HIGH, PLM_NOFLAGS, 0, "/home/samba" }, { HIGH, PLM_NOFLAGS, 0, "/usr/home/samba" }, { LOW, PLM_NOFLAGS, 0, "/dev/printer" }, { HIGH, PLM_CHILDOF, 0, "/var/log" }, { LOW, PLM_NOFLAGS, 0, "/var/log/sendmail.st" }, { HIGH, PLM_NOFLAGS, LOWWRITE, "/var/run/utmp" }, { HIGH, PLM_NOFLAGS, LOWWRITE, "/var/log/lastlog" }, { HIGH, PLM_NOFLAGS, LOWWRITE, "/var/log/wtmp" }, { 0, 0, 0 } }; #endif /* LOMAC_PLM_H */ diff --git a/sys/security/lomac/syscall_gate.c b/sys/security/lomac/syscall_gate.c index 56817fc86446..70eb9afd8b46 100644 --- a/sys/security/lomac/syscall_gate.c +++ b/sys/security/lomac/syscall_gate.c @@ -1,125 +1,125 @@ /*- - * Copyright (c) 2001 Networks Associates Technologies, Inc. + * Copyright (c) 2001 Networks Associates Technology, Inc. * All rights reserved. * * This software was developed for the FreeBSD Project by NAI Labs, the * Security Research Division of Network Associates, Inc. under * DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA * CHATS research program. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $Id$ * $FreeBSD$ */ #include #include #include #include #include #include #include #include #include #include #include #include "syscall_gate.h" void syscall_gate_init(void); int syscall_gate(struct thread *td, caddr_t params); static struct syscall_gate sg; void syscall_gate_init(void) { sg.sg_table = curthread->td_proc->p_sysent->sv_table; bzero(sg.sg_oldsyscalls, sizeof(sg.sg_oldsyscalls)); } int syscall_gate_register(int offset, sy_call_t *call, int narg, int mpsafe) { struct sysent *se; int error = 0; if (offset <= 0 || offset >= SYS_MAXSYSCALL) { error = EINVAL; goto out; } if (sg.sg_oldsyscalls[offset].sy_call != NULL) { error = EEXIST; goto out; } se = &sg.sg_table[offset]; sg.sg_oldsyscalls[offset] = *se; se->sy_call = (sy_call_t *)call; se->sy_narg = narg | (mpsafe ? SYF_MPSAFE : 0); out: return (error); } void syscall_gate_deregister(int offset) { KASSERT(offset > 0 && offset < SYS_MAXSYSCALL, ("syscall offset %d out of range", offset)); KASSERT(sg.sg_oldsyscalls[offset].sy_call != NULL, ("deregistering nonexistant syscall %d", offset)); sg.sg_table[offset] = sg.sg_oldsyscalls[offset]; sg.sg_oldsyscalls[offset].sy_call = NULL; sg.sg_oldsyscalls[offset].sy_narg = 0; } static int syscall_gate_modevent(module_t module, int event, void *unused) { int i; switch ((enum modeventtype)event) { case MOD_LOAD: syscall_gate_init(); break; case MOD_UNLOAD: for (i = 1; i < SYS_MAXSYSCALL; i++) { struct sysent *se; se = &sg.sg_oldsyscalls[i]; if (se->sy_call != NULL) sg.sg_table[i] = *se; } break; case MOD_SHUTDOWN: break; } return (0); } static moduledata_t syscall_gate_moduledata = { "syscall_gate", &syscall_gate_modevent, NULL }; DECLARE_MODULE(syscall_gate, syscall_gate_moduledata, SI_SUB_DRIVERS, SI_ORDER_ANY); MODULE_VERSION(syscall_gate, 1); diff --git a/sys/security/lomac/syscall_gate.h b/sys/security/lomac/syscall_gate.h index 9546bea5c90f..1ee5c7439b8c 100644 --- a/sys/security/lomac/syscall_gate.h +++ b/sys/security/lomac/syscall_gate.h @@ -1,56 +1,56 @@ /*- - * Copyright (c) 2001 Networks Associates Technologies, Inc. + * Copyright (c) 2001 Networks Associates Technology, Inc. * All rights reserved. * * This software was developed for the FreeBSD Project by NAI Labs, the * Security Research Division of Network Associates, Inc. under * DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA * CHATS research program. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $Id$ * $FreeBSD$ */ #ifndef SYSCALL_GATE_H #define SYSCALL_GATE_H #include #include #include #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 */