079b7badea
this is a low-functionality change that changes the kernel to access the main thread of a process via the linked list of threads rather than assuming that it is embedded in the process. It IS still embeded there but remove all teh code that assumes that in preparation for the next commit which will actually move it out. Reviewed by: peter@freebsd.org, gallatin@cs.duke.edu, benno rice,
697 lines
16 KiB
C
697 lines
16 KiB
C
/*-
|
|
* Copyright (c) 2001 Networks Associates Technologies, Inc.
|
|
* Copyright (c) 1982, 1986, 1989, 1991, 1993
|
|
* The Regents of the University of California. All rights reserved.
|
|
* (c) UNIX System Laboratories, Inc.
|
|
|
|
* This software was developed for the FreeBSD Project by NAI Labs, the
|
|
* Security Research Division of Network Associates, Inc. under
|
|
* DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA
|
|
* CHATS research program.
|
|
*
|
|
* All or some portions of this file are derived from material licensed
|
|
* to the University of California by American Telephone and Telegraph
|
|
* Co. or Unix System Laboratories, Inc. and are reproduced herein with
|
|
* the permission of UNIX System Laboratories, Inc.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* 3. The name of the author may not be used to endorse or promote
|
|
* products derived from this software without specific prior written
|
|
* permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
* SUCH DAMAGE.
|
|
*
|
|
* $Id$
|
|
* $FreeBSD$
|
|
*/
|
|
|
|
#include <sys/param.h>
|
|
#include <sys/proc.h>
|
|
#include <sys/lock.h>
|
|
#include <sys/mutex.h>
|
|
#include <sys/signalvar.h>
|
|
#include <sys/sx.h>
|
|
#include <sys/syscall.h>
|
|
#include <sys/sysent.h>
|
|
#include <sys/sysproto.h>
|
|
#include <sys/systm.h>
|
|
#include <sys/linker.h>
|
|
#include <sys/mount.h>
|
|
#include <sys/mman.h>
|
|
#include <sys/dirent.h>
|
|
#include <sys/namei.h>
|
|
#include <sys/uio.h>
|
|
#include <sys/unistd.h>
|
|
|
|
#include <vm/vm.h>
|
|
#include <vm/vm_extern.h>
|
|
#include <vm/vm_kern.h>
|
|
|
|
#include "kernel_interface.h"
|
|
#include "kernel_util.h"
|
|
#include "kernel_mediate.h"
|
|
#include "kernel_monitor.h"
|
|
#include "lomacfs.h"
|
|
|
|
#include "syscall_gate.h"
|
|
|
|
#define AS(name) (sizeof(struct name) / sizeof(register_t))
|
|
|
|
int
|
|
each_proc(int (*iter)(struct proc *p)) {
|
|
struct proc *p;
|
|
int error = 0;
|
|
|
|
sx_slock(&allproc_lock);
|
|
LIST_FOREACH(p, &allproc, p_list) {
|
|
error = (*iter)(p);
|
|
if (error)
|
|
goto out;
|
|
}
|
|
out:
|
|
sx_sunlock(&allproc_lock);
|
|
return (error);
|
|
}
|
|
|
|
static int
|
|
initialize_proc(struct proc *p) {
|
|
lattr_t lattr = { LOMAC_HIGHEST_LEVEL, 0 };
|
|
|
|
init_subject_lattr(p, &lattr);
|
|
return (0);
|
|
}
|
|
|
|
static void
|
|
lomac_at_fork(struct proc *parent, struct proc *p, int flags) {
|
|
|
|
if ((flags & RFMEM) == 0) {
|
|
lattr_t parent_lattr;
|
|
|
|
get_subject_lattr(parent, &parent_lattr);
|
|
init_subject_lattr(p, &parent_lattr);
|
|
}
|
|
}
|
|
|
|
static int
|
|
lomac_proc_candebug(struct proc *p1, struct proc *p2) {
|
|
lattr_t lattr;
|
|
|
|
get_subject_lattr(p1, &lattr);
|
|
if (mediate_subject_level_subject("debug", p1, lattr.level, p2))
|
|
return (0);
|
|
else
|
|
return (EPERM);
|
|
}
|
|
|
|
static int
|
|
lomac_proc_cansched(struct proc *p1, struct proc *p2) {
|
|
lattr_t lattr;
|
|
|
|
get_subject_lattr(p1, &lattr);
|
|
if (mediate_subject_level_subject("sched", p1, lattr.level, p2))
|
|
return (0);
|
|
else
|
|
return (EPERM);
|
|
}
|
|
|
|
static int
|
|
lomac_proc_cansignal(struct proc *p1, struct proc *p2, int signum) {
|
|
lattr_t lattr;
|
|
|
|
get_subject_lattr(p1, &lattr);
|
|
/*
|
|
* Always allow signals to init(8) (necessary to shut down).
|
|
*/
|
|
if (p2->p_pid == 1 ||
|
|
mediate_subject_level_subject("signal", p1, lattr.level, p2))
|
|
return (0);
|
|
else
|
|
return (EPERM);
|
|
}
|
|
|
|
|
|
int
|
|
lomac_initialize_procs(void) {
|
|
int error;
|
|
|
|
#ifdef P_CAN_HOOKS
|
|
can_hooks_lock();
|
|
(void)p_candebug_hook(lomac_proc_candebug);
|
|
(void)p_cansignal_hook(lomac_proc_cansignal);
|
|
(void)p_cansched_hook(lomac_proc_cansched);
|
|
can_hooks_unlock();
|
|
#endif
|
|
error = at_fork(lomac_at_fork);
|
|
if (error)
|
|
return (error);
|
|
return (each_proc(&initialize_proc));
|
|
}
|
|
|
|
int
|
|
lomac_uninitialize_procs(void) {
|
|
|
|
rm_at_fork(lomac_at_fork);
|
|
return (0);
|
|
}
|
|
|
|
extern int (*old_execve)(struct thread *, struct execve_args *);
|
|
|
|
int
|
|
execve(struct thread *td, struct execve_args *uap) {
|
|
lattr_t lattr, textattr;
|
|
struct vmspace *oldvmspace;
|
|
struct proc *p;
|
|
int error;
|
|
|
|
p = td->td_proc;
|
|
get_subject_lattr(p, &lattr);
|
|
oldvmspace = p->p_vmspace;
|
|
error = old_execve(td, uap);
|
|
if (error == 0) {
|
|
lomac_object_t lobj;
|
|
|
|
lobj.lo_type = VISLOMAC(p->p_textvp) ? LO_TYPE_LVNODE :
|
|
LO_TYPE_UVNODE;
|
|
lobj.lo_object.vnode = p->p_textvp;
|
|
get_object_lattr(&lobj, &textattr);
|
|
/*
|
|
* Install the executable's relevant attributes into the
|
|
* process.
|
|
*/
|
|
lattr.flags |= textattr.flags &
|
|
(LOMAC_ATTR_NODEMOTE | LOMAC_ATTR_NONETDEMOTE);
|
|
if (p->p_vmspace != oldvmspace)
|
|
init_subject_lattr(p, &lattr);
|
|
else
|
|
set_subject_lattr(p, lattr);
|
|
mtx_lock(&Giant);
|
|
(void)monitor_read_object(p, &lobj);
|
|
mtx_unlock(&Giant);
|
|
}
|
|
return (error);
|
|
}
|
|
|
|
const char *linker_basename(const char* path);
|
|
int linker_load_module(const char *kldname, const char *modname,
|
|
struct linker_file *parent, struct mod_depend *verinfo,
|
|
struct linker_file **lfpp);
|
|
|
|
MALLOC_DECLARE(M_LINKER);
|
|
|
|
/*
|
|
* MPSAFE
|
|
*/
|
|
int
|
|
kldload(struct thread* td, struct kldload_args* uap)
|
|
{
|
|
char *kldname, *modname;
|
|
char *pathname = NULL;
|
|
linker_file_t lf;
|
|
int error = 0;
|
|
|
|
td->td_retval[0] = -1;
|
|
|
|
if (securelevel > 0) /* redundant, but that's OK */
|
|
return EPERM;
|
|
|
|
mtx_lock(&Giant);
|
|
|
|
if ((error = suser_td(td)) != 0)
|
|
goto out;
|
|
|
|
pathname = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
|
|
if ((error = copyinstr(SCARG(uap, file), pathname, MAXPATHLEN, NULL)) != 0)
|
|
goto out;
|
|
if (!mediate_subject_at_level("kldload", td->td_proc,
|
|
LOMAC_HIGHEST_LEVEL)) {
|
|
error = EPERM;
|
|
goto out;
|
|
}
|
|
|
|
/*
|
|
* If path do not contain qualified name or any dot in it (kldname.ko, or
|
|
* kldname.ver.ko) treat it as interface name.
|
|
*/
|
|
if (index(pathname, '/') || index(pathname, '.')) {
|
|
kldname = pathname;
|
|
modname = NULL;
|
|
} else {
|
|
kldname = NULL;
|
|
modname = pathname;
|
|
}
|
|
error = linker_load_module(kldname, modname, NULL, NULL, &lf);
|
|
if (error)
|
|
goto out;
|
|
|
|
lf->userrefs++;
|
|
td->td_retval[0] = lf->id;
|
|
|
|
out:
|
|
if (pathname)
|
|
free(pathname, M_TEMP);
|
|
mtx_unlock(&Giant);
|
|
return (error);
|
|
}
|
|
|
|
|
|
#ifdef __i386__
|
|
#include <machine/sysarch.h>
|
|
|
|
extern int (*old_sysarch)(struct thread *, void *);
|
|
|
|
int
|
|
sysarch(struct thread *td, struct sysarch_args *uap) {
|
|
switch (uap->op) {
|
|
case I386_SET_IOPERM:
|
|
if (!mediate_subject_at_level("ioperm", td->td_proc,
|
|
LOMAC_HIGHEST_LEVEL))
|
|
return (EPERM);
|
|
default:
|
|
return (old_sysarch(td, uap));
|
|
}
|
|
}
|
|
#endif
|
|
|
|
extern int lomac_mmap(struct proc *, struct mmap_args *);
|
|
|
|
/*
|
|
* Mount a file system.
|
|
*/
|
|
#ifndef _SYS_SYSPROTO_H_
|
|
struct mount_args {
|
|
char *type;
|
|
char *path;
|
|
int flags;
|
|
caddr_t data;
|
|
};
|
|
#endif
|
|
/* ARGSUSED */
|
|
int
|
|
mount(td, uap)
|
|
struct thread *td;
|
|
struct mount_args /* {
|
|
syscallarg(char *) type;
|
|
syscallarg(char *) path;
|
|
syscallarg(int) flags;
|
|
syscallarg(caddr_t) data;
|
|
} */ *uap;
|
|
{
|
|
char *fstype;
|
|
char *fspath;
|
|
int error;
|
|
|
|
fstype = malloc(MFSNAMELEN, M_TEMP, M_WAITOK | M_ZERO);
|
|
fspath = malloc(MNAMELEN, M_TEMP, M_WAITOK | M_ZERO);
|
|
|
|
/*
|
|
* vfs_mount() actually takes a kernel string for `type' and
|
|
* `path' now, so extract them.
|
|
*/
|
|
error = copyinstr(SCARG(uap, type), fstype, MFSNAMELEN, NULL);
|
|
if (error)
|
|
goto finish;
|
|
error = copyinstr(SCARG(uap, path), fspath, MNAMELEN, NULL);
|
|
if (error)
|
|
goto finish;
|
|
if (!mediate_subject_at_level("mount", td->td_proc,
|
|
LOMAC_HIGHEST_LEVEL)) {
|
|
error = EPERM;
|
|
goto finish;
|
|
}
|
|
error = vfs_mount(td, fstype, fspath, SCARG(uap, flags),
|
|
SCARG(uap, data));
|
|
finish:
|
|
free(fstype, M_TEMP);
|
|
free(fspath, M_TEMP);
|
|
return (error);
|
|
}
|
|
|
|
/*
|
|
* Unmount a file system.
|
|
*
|
|
* Note: unmount takes a path to the vnode mounted on as argument,
|
|
* not special file (as before).
|
|
*/
|
|
#ifndef _SYS_SYSPROTO_H_
|
|
struct unmount_args {
|
|
char *path;
|
|
int flags;
|
|
};
|
|
#endif
|
|
/* ARGSUSED */
|
|
int
|
|
unmount(td, uap)
|
|
struct thread *td;
|
|
register struct unmount_args /* {
|
|
syscallarg(char *) path;
|
|
syscallarg(int) flags;
|
|
} */ *uap;
|
|
{
|
|
register struct vnode *vp;
|
|
struct mount *mp;
|
|
int error;
|
|
struct nameidata nd;
|
|
|
|
NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
|
|
SCARG(uap, path), td);
|
|
if ((error = namei(&nd)) != 0)
|
|
return (error);
|
|
vp = nd.ni_vp;
|
|
NDFREE(&nd, NDF_ONLY_PNBUF);
|
|
mp = vp->v_mount;
|
|
|
|
/*
|
|
* Only root, or the user that did the original mount is
|
|
* permitted to unmount this filesystem.
|
|
*/
|
|
if (!mediate_subject_at_level("unmount", td->td_proc,
|
|
LOMAC_HIGHEST_LEVEL) ||
|
|
((mp->mnt_stat.f_owner != td->td_proc->p_ucred->cr_uid) &&
|
|
(error = suser_td(td)))) {
|
|
vput(vp);
|
|
return (error);
|
|
}
|
|
|
|
/*
|
|
* Don't allow unmounting the root file system.
|
|
*/
|
|
if (mp->mnt_flag & MNT_ROOTFS) {
|
|
vput(vp);
|
|
return (EINVAL);
|
|
}
|
|
|
|
/*
|
|
* Must be the root of the filesystem
|
|
*/
|
|
if ((vp->v_flag & VROOT) == 0) {
|
|
vput(vp);
|
|
return (EINVAL);
|
|
}
|
|
vput(vp);
|
|
return (dounmount(mp, SCARG(uap, flags), td));
|
|
}
|
|
|
|
static struct syscall_override {
|
|
int offset;
|
|
sy_call_t *call;
|
|
int narg;
|
|
int mpsafe;
|
|
} syscall_overrides[] = {
|
|
{ SYS_mmap, (sy_call_t *)mmap, AS(mmap_args), 1 },
|
|
{ SYS_execve, (sy_call_t *)execve, AS(execve_args), 1 },
|
|
{ SYS_kldload, (sy_call_t *)kldload, AS(kldload_args), 1 },
|
|
{ SYS_mount, (sy_call_t *)mount, AS(mount_args), 0 },
|
|
{ SYS_unmount, (sy_call_t *)unmount, AS(unmount_args), 0 },
|
|
#ifdef __i386__
|
|
{ SYS_sysarch, (sy_call_t *)sysarch, AS(sysarch_args), 1 }
|
|
#endif
|
|
};
|
|
|
|
int
|
|
lomac_initialize_syscalls(void) {
|
|
int error, i;
|
|
|
|
for (i = 0;
|
|
i < sizeof(syscall_overrides) / sizeof(syscall_overrides[0]); i++) {
|
|
struct syscall_override *so = &syscall_overrides[i];
|
|
|
|
error = syscall_gate_register(so->offset, so->call, so->narg,
|
|
so->mpsafe);
|
|
if (error) {
|
|
while (--i >= 0)
|
|
syscall_gate_deregister(
|
|
syscall_overrides[i].offset);
|
|
return (error);
|
|
}
|
|
}
|
|
return (0);
|
|
}
|
|
|
|
int
|
|
lomac_uninitialize_syscalls(void) {
|
|
int i;
|
|
|
|
for (i = 0;
|
|
i < sizeof(syscall_overrides) / sizeof(syscall_overrides[0]); i++)
|
|
syscall_gate_deregister(syscall_overrides[i].offset);
|
|
return (0);
|
|
}
|
|
|
|
/* This memory is shared by all lomac_do_recwd() calls, in sequence. */
|
|
static char *pathmem;
|
|
#define DIRENTMEM_SIZE (64 << 10) /* 64KB is good, I guess! */
|
|
static char *direntmem;
|
|
|
|
static int
|
|
lomac_dirents_searchbyid(struct vnode *dvp, struct dirent *dp,
|
|
struct dirent *enddp, const struct vattr *vap, struct dirent **retdp)
|
|
{
|
|
struct vattr pvattr;
|
|
struct componentname cnp;
|
|
struct thread *td = curthread;
|
|
struct ucred *ucred = td->td_ucred;
|
|
struct vnode *vp;
|
|
int error;
|
|
|
|
*retdp = NULL;
|
|
for (; dp != enddp; dp = (struct dirent *)((char *)dp + dp->d_reclen)) {
|
|
cnp.cn_nameiop = LOOKUP;
|
|
cnp.cn_flags = LOCKPARENT | ISLASTCN | NOFOLLOW;
|
|
cnp.cn_thread = td;
|
|
cnp.cn_cred = ucred;
|
|
cnp.cn_nameptr = dp->d_name;
|
|
cnp.cn_namelen = dp->d_namlen;
|
|
|
|
error = VOP_LOOKUP(dvp, &vp, &cnp);
|
|
if (error)
|
|
return (error);
|
|
error = VOP_GETATTR(vp, &pvattr, ucred, td);
|
|
if (vp != dvp)
|
|
(void)vput(vp);
|
|
else
|
|
vrele(vp); /* if looking up "." */
|
|
if (error)
|
|
return (error);
|
|
if (pvattr.va_fsid == vap->va_fsid &&
|
|
pvattr.va_fileid == vap->va_fileid) {
|
|
*retdp = dp;
|
|
break;
|
|
}
|
|
}
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
lomac_getcwd(
|
|
struct thread *td,
|
|
char *buf,
|
|
size_t buflen,
|
|
char **bufret
|
|
) {
|
|
struct vattr cvattr;
|
|
char *bp;
|
|
int error, i, slash_prefixed;
|
|
struct filedesc *fdp;
|
|
struct vnode *vp, *startvp, *dvp;
|
|
|
|
if (buflen < 2)
|
|
return (EINVAL);
|
|
if (buflen > MAXPATHLEN)
|
|
buflen = MAXPATHLEN;
|
|
bp = buf;
|
|
bp += buflen - 1;
|
|
*bp = '\0';
|
|
fdp = td->td_proc->p_fd;
|
|
slash_prefixed = 0;
|
|
#if defined(LOMAC_DEBUG_RECWD)
|
|
printf("lomac_getcwd for %d:\n", td->td_proc->p_pid);
|
|
#endif
|
|
startvp = fdp->fd_cdir;
|
|
vref(startvp);
|
|
for (vp = startvp; vp != rootvnode; vp = dvp) {
|
|
struct iovec diov = {
|
|
direntmem,
|
|
DIRENTMEM_SIZE
|
|
};
|
|
struct uio duio = {
|
|
&diov,
|
|
1,
|
|
0,
|
|
DIRENTMEM_SIZE,
|
|
UIO_SYSSPACE,
|
|
UIO_READ,
|
|
curthread
|
|
};
|
|
struct dirent *dp;
|
|
int direof;
|
|
|
|
if (vp->v_flag & VROOT) {
|
|
if (vp->v_mount == NULL) /* forced unmount */
|
|
return (EBADF);
|
|
dvp = vp->v_mount->mnt_vnodecovered;
|
|
continue;
|
|
}
|
|
dvp = vp->v_dd;
|
|
if (vp == dvp)
|
|
break;
|
|
/*
|
|
* Utilize POSIX requirement of files having same
|
|
* st_dev and st_ino to be the same file, in our
|
|
* case with vattr.va_fsid and vattr.va_fileid.
|
|
*/
|
|
error = vget(vp, LK_EXCLUSIVE, curthread);
|
|
if (error)
|
|
goto out2;
|
|
error = VOP_GETATTR(vp, &cvattr, curthread->td_ucred,
|
|
curthread);
|
|
if (error)
|
|
goto out2;
|
|
(void)vput(vp);
|
|
error = vget(dvp, LK_EXCLUSIVE, curthread);
|
|
if (error)
|
|
goto out2;
|
|
for (direof = 0; !direof;) {
|
|
error = VOP_READDIR(dvp, &duio,
|
|
curthread->td_ucred, &direof, NULL, NULL);
|
|
if (error)
|
|
break;
|
|
error = lomac_dirents_searchbyid(dvp,
|
|
(struct dirent *)direntmem,
|
|
(struct dirent *)(direntmem +
|
|
DIRENTMEM_SIZE - duio.uio_resid),
|
|
&cvattr,
|
|
&dp);
|
|
if (error)
|
|
break;
|
|
if (dp != NULL) {
|
|
(void)vput(dvp);
|
|
#if defined(LOMAC_DEBUG_RECWD)
|
|
printf("\tdirent component: \"%.*s\"\n",
|
|
dp->d_namlen, dp->d_name);
|
|
#endif
|
|
for (i = dp->d_namlen - 1; i >= 0; i--)
|
|
if (bp == buf)
|
|
return (ENOMEM);
|
|
else
|
|
*--bp = dp->d_name[i];
|
|
goto nextcomp;
|
|
}
|
|
diov.iov_base = direntmem;
|
|
diov.iov_len = DIRENTMEM_SIZE;
|
|
duio.uio_resid = DIRENTMEM_SIZE;
|
|
}
|
|
if (direof)
|
|
error = ENOENT;
|
|
(void)vput(dvp);
|
|
out2:
|
|
#if defined(LOMAC_DEBUG_RECWD)
|
|
printf("backup dirent lookup problem: %d\n", error);
|
|
#endif
|
|
goto out;
|
|
nextcomp:
|
|
if (bp == buf)
|
|
return (ENOMEM);
|
|
*--bp = '/';
|
|
slash_prefixed = 1;
|
|
}
|
|
if (!slash_prefixed) {
|
|
if (bp == buf)
|
|
return (ENOMEM);
|
|
*--bp = '/';
|
|
}
|
|
error = 0;
|
|
*bufret = bp;
|
|
out:
|
|
vrele(startvp);
|
|
return (error);
|
|
}
|
|
|
|
static int
|
|
lomac_do_recwd(struct proc *p) {
|
|
struct nameidata nd;
|
|
struct filedesc *fdp = curthread->td_proc->p_fd;
|
|
struct thread *td = 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_proc->p_ucred,
|
|
curthread);
|
|
if (error)
|
|
vput(vp);
|
|
else {
|
|
NDFREE(&nd, NDF_ONLY_PNBUF);
|
|
fdp = p->p_fd;
|
|
cdir = fdp->fd_cdir;
|
|
fdp->fd_cdir = vp;
|
|
vrele(cdir);
|
|
VOP_UNLOCK(vp, 0, curthread);
|
|
}
|
|
}
|
|
#if defined(LOMAC_DEBUG_RECWD)
|
|
printf("\trecwd() to \"%.*s\" == %d\n",
|
|
MAXPATHLEN, nbuf, error);
|
|
#endif
|
|
return (0);
|
|
}
|
|
|
|
int
|
|
lomac_initialize_cwds(void) {
|
|
int error;
|
|
|
|
pathmem = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
|
|
direntmem = malloc(DIRENTMEM_SIZE, M_TEMP, M_WAITOK);
|
|
mtx_lock(&Giant);
|
|
error = each_proc(lomac_do_recwd);
|
|
mtx_unlock(&Giant);
|
|
free(pathmem, M_TEMP);
|
|
free(direntmem, M_TEMP);
|
|
return (error);
|
|
}
|