Add the 'filemon' device. 'filemon' is a kernel module that provides a device

interface for processes to record system calls of its children.

Submitted by:	Juniper Networks.
This commit is contained in:
obrien 2012-06-04 22:54:19 +00:00
parent 0dd8d2fe74
commit 316161913d
6 changed files with 1292 additions and 0 deletions

377
sys/dev/filemon/filemon.c Normal file
View File

@ -0,0 +1,377 @@
/*-
* Copyright (c) 2011, David E. O'Brien.
* Copyright (c) 2009-2011, Juniper Networks, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY JUNIPER NETWORKS 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 JUNIPER NETWORKS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/file.h>
#include <sys/systm.h>
#include <sys/buf.h>
#include <sys/condvar.h>
#include <sys/conf.h>
#include <sys/fcntl.h>
#include <sys/ioccom.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/module.h>
#include <sys/mutex.h>
#include <sys/poll.h>
#include <sys/proc.h>
#include <sys/queue.h>
#include <sys/syscall.h>
#include <sys/sysent.h>
#include <sys/sysproto.h>
#include <sys/uio.h>
#if __FreeBSD_version >= 900041
#include <sys/capability.h>
#endif
#include "filemon.h"
#if defined(COMPAT_IA32) || defined(COMPAT_FREEBSD32) || defined(COMPAT_ARCH32)
#include <compat/freebsd32/freebsd32_syscall.h>
#include <compat/freebsd32/freebsd32_proto.h>
extern struct sysentvec ia32_freebsd_sysvec;
#endif
extern struct sysentvec elf32_freebsd_sysvec;
extern struct sysentvec elf64_freebsd_sysvec;
static d_close_t filemon_close;
static d_ioctl_t filemon_ioctl;
static d_open_t filemon_open;
static int filemon_unload(void);
static void filemon_load(void *);
static struct cdevsw filemon_cdevsw = {
.d_version = D_VERSION,
.d_close = filemon_close,
.d_ioctl = filemon_ioctl,
.d_open = filemon_open,
.d_name = "filemon",
};
MALLOC_DECLARE(M_FILEMON);
MALLOC_DEFINE(M_FILEMON, "filemon", "File access monitor");
struct filemon {
TAILQ_ENTRY(filemon) link; /* Link into the in-use list. */
struct mtx mtx; /* Lock mutex for this filemon. */
struct cv cv; /* Lock condition variable for this
filemon. */
struct file *fp; /* Output file pointer. */
struct thread *locker; /* Ptr to the thread locking this
filemon. */
pid_t pid; /* The process ID being monitored. */
char fname1[MAXPATHLEN]; /* Temporary filename buffer. */
char fname2[MAXPATHLEN]; /* Temporary filename buffer. */
char msgbufr[1024]; /* Output message buffer. */
};
static TAILQ_HEAD(, filemon) filemons_inuse = TAILQ_HEAD_INITIALIZER(filemons_inuse);
static TAILQ_HEAD(, filemon) filemons_free = TAILQ_HEAD_INITIALIZER(filemons_free);
static int n_readers = 0;
static struct mtx access_mtx;
static struct cv access_cv;
static struct thread *access_owner = NULL;
static struct thread *access_requester = NULL;
#if __FreeBSD_version < 701000
static struct clonedevs *filemon_clones;
static eventhandler_tag eh_tag;
#else
static struct cdev *filemon_dev;
#endif
#include "filemon_lock.c"
#include "filemon_wrapper.c"
#if __FreeBSD_version < 701000
static void
filemon_clone(void *arg, struct ucred *cred, char *name, int namelen,
struct cdev **dev)
{
int u = -1;
size_t len;
if (*dev != NULL)
return;
len = strlen(name);
if (len != 7)
return;
if (bcmp(name,"filemon", 7) != 0)
return;
/* Clone the device to the new minor number. */
if (clone_create(&filemon_clones, &filemon_cdevsw, &u, dev, 0) != 0)
/* Create the /dev/filemonNN entry. */
*dev = make_dev_cred(&filemon_cdevsw, u, cred, UID_ROOT,
GID_WHEEL, 0666, "filemon%d", u);
if (*dev != NULL) {
dev_ref(*dev);
(*dev)->si_flags |= SI_CHEAPCLONE;
}
}
#endif
static void
filemon_dtr(void *data)
{
struct filemon *filemon = data;
if (filemon != NULL) {
struct file *fp = filemon->fp;
/* Get exclusive write access. */
filemon_lock_write();
/* Remove from the in-use list. */
TAILQ_REMOVE(&filemons_inuse, filemon, link);
filemon->fp = NULL;
filemon->pid = -1;
/* Add to the free list. */
TAILQ_INSERT_TAIL(&filemons_free, filemon, link);
/* Give up write access. */
filemon_unlock_write();
if (fp != NULL)
fdrop(fp, curthread);
}
}
static int
filemon_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag __unused,
struct thread *td)
{
int error = 0;
struct filemon *filemon;
#if __FreeBSD_version < 701000
filemon = dev->si_drv1;
#else
devfs_get_cdevpriv((void **) &filemon);
#endif
switch (cmd) {
/* Set the output file descriptor. */
case FILEMON_SET_FD:
#if __FreeBSD_version < 900041
#define FGET_WRITE(a1, a2, a3) fget_write((a1), (a2), (a3))
#else
#define FGET_WRITE(a1, a2, a3) fget_write((a1), (a2), CAP_WRITE | CAP_SEEK, (a3))
#endif
if ((error = FGET_WRITE(td, *(int *)data, &filemon->fp)) == 0)
/* Write the file header. */
filemon_comment(filemon);
break;
/* Set the monitored process ID. */
case FILEMON_SET_PID:
filemon->pid = *((pid_t *) data);
break;
default:
error = EINVAL;
break;
}
return (error);
}
static int
filemon_open(struct cdev *dev, int oflags __unused, int devtype __unused,
struct thread *td __unused)
{
struct filemon *filemon;
/* Get exclusive write access. */
filemon_lock_write();
if ((filemon = TAILQ_FIRST(&filemons_free)) != NULL)
TAILQ_REMOVE(&filemons_free, filemon, link);
/* Give up write access. */
filemon_unlock_write();
if (filemon == NULL) {
filemon = malloc(sizeof(struct filemon), M_FILEMON,
M_WAITOK | M_ZERO);
filemon->fp = NULL;
mtx_init(&filemon->mtx, "filemon", "filemon", MTX_DEF);
cv_init(&filemon->cv, "filemon");
}
filemon->pid = curproc->p_pid;
#if __FreeBSD_version < 701000
dev->si_drv1 = filemon;
#else
devfs_set_cdevpriv(filemon, filemon_dtr);
#endif
/* Get exclusive write access. */
filemon_lock_write();
/* Add to the in-use list. */
TAILQ_INSERT_TAIL(&filemons_inuse, filemon, link);
/* Give up write access. */
filemon_unlock_write();
return (0);
}
static int
filemon_close(struct cdev *dev __unused, int flag __unused, int fmt __unused,
struct thread *td __unused)
{
#if __FreeBSD_version < 701000
filemon_dtr(dev->si_drv1);
dev->si_drv1 = NULL;
/* Schedule this cloned device to be destroyed. */
destroy_dev_sched(dev);
#endif
return (0);
}
static void
filemon_load(void *dummy __unused)
{
mtx_init(&access_mtx, "filemon", "filemon", MTX_DEF);
cv_init(&access_cv, "filemon");
/* Install the syscall wrappers. */
filemon_wrapper_install();
#if __FreeBSD_version < 701000
/* Enable device cloning. */
clone_setup(&filemon_clones);
/* Setup device cloning events. */
eh_tag = EVENTHANDLER_REGISTER(dev_clone, filemon_clone, 0, 1000);
#else
filemon_dev = make_dev(&filemon_cdevsw, 0, UID_ROOT, GID_WHEEL, 0666,
"filemon");
#endif
}
static int
filemon_unload(void)
{
struct filemon *filemon;
int error = 0;
/* Get exclusive write access. */
filemon_lock_write();
if (TAILQ_FIRST(&filemons_inuse) != NULL)
error = EBUSY;
else {
#if __FreeBSD_version >= 701000
destroy_dev(filemon_dev);
#endif
/* Deinstall the syscall wrappers. */
filemon_wrapper_deinstall();
}
/* Give up write access. */
filemon_unlock_write();
if (error == 0) {
#if __FreeBSD_version < 701000
/*
* Check if there is still an event handler callback registered.
*/
if (eh_tag != 0) {
/* De-register the device cloning event handler. */
EVENTHANDLER_DEREGISTER(dev_clone, eh_tag);
eh_tag = 0;
/* Stop device cloning. */
clone_cleanup(&filemon_clones);
}
#endif
/* free() filemon structs free list. */
filemon_lock_write();
while ((filemon = TAILQ_FIRST(&filemons_free)) != NULL) {
TAILQ_REMOVE(&filemons_free, filemon, link);
mtx_destroy(&filemon->mtx);
cv_destroy(&filemon->cv);
free(filemon, M_FILEMON);
}
filemon_unlock_write();
mtx_destroy(&access_mtx);
cv_destroy(&access_cv);
}
return (error);
}
static int
filemon_modevent(module_t mod __unused, int type, void *data)
{
int error = 0;
switch (type) {
case MOD_LOAD:
filemon_load(data);
break;
case MOD_UNLOAD:
error = filemon_unload();
break;
case MOD_SHUTDOWN:
break;
default:
error = EOPNOTSUPP;
break;
}
return (error);
}
DEV_MODULE(filemon, filemon_modevent, NULL);
MODULE_VERSION(filemon, 1);

34
sys/dev/filemon/filemon.h Normal file
View File

@ -0,0 +1,34 @@
/*-
* Copyright (c) 2011, David E. O'Brien.
* Copyright (c) 2009-2011, Juniper Networks, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY JUNIPER NETWORKS 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 JUNIPER NETWORKS 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$
*/
#define FILEMON_SET_FD _IOWR('S', 1, int)
#define FILEMON_SET_PID _IOWR('S', 2, pid_t)
#define FILEMON_VERSION 4 /* output format
(bump when adding record types) */

View File

@ -0,0 +1,122 @@
/*-
* Copyright (c) 2009-2011, Juniper Networks, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY JUNIPER NETWORKS 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 JUNIPER NETWORKS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
static void
filemon_filemon_lock(struct filemon *filemon)
{
mtx_lock(&filemon->mtx);
while (filemon->locker != NULL && filemon->locker != curthread)
cv_wait(&filemon->cv, &filemon->mtx);
filemon->locker = curthread;
mtx_unlock(&filemon->mtx);
}
static void
filemon_filemon_unlock(struct filemon *filemon)
{
mtx_lock(&filemon->mtx);
if (filemon->locker == curthread)
filemon->locker = NULL;
/* Wake up threads waiting. */
cv_broadcast(&filemon->cv);
mtx_unlock(&filemon->mtx);
}
static void
filemon_lock_read(void)
{
mtx_lock(&access_mtx);
while (access_owner != NULL || access_requester != NULL)
cv_wait(&access_cv, &access_mtx);
n_readers++;
/* Wake up threads waiting. */
cv_broadcast(&access_cv);
mtx_unlock(&access_mtx);
}
static void
filemon_unlock_read(void)
{
mtx_lock(&access_mtx);
if (n_readers > 0)
n_readers--;
/* Wake up a thread waiting. */
cv_broadcast(&access_cv);
mtx_unlock(&access_mtx);
}
static void
filemon_lock_write(void)
{
mtx_lock(&access_mtx);
while (access_owner != curthread) {
if (access_owner == NULL &&
(access_requester == NULL ||
access_requester == curthread)) {
access_owner = curthread;
access_requester = NULL;
} else {
if (access_requester == NULL)
access_requester = curthread;
cv_wait(&access_cv, &access_mtx);
}
}
mtx_unlock(&access_mtx);
}
static void
filemon_unlock_write(void)
{
mtx_lock(&access_mtx);
/* Sanity check that the current thread actually has the write lock. */
if (access_owner == curthread)
access_owner = NULL;
/* Wake up a thread waiting. */
cv_broadcast(&access_cv);
mtx_unlock(&access_mtx);
}

View File

@ -0,0 +1,746 @@
/*-
* Copyright (c) 2011, David E. O'Brien.
* Copyright (c) 2009-2011, Juniper Networks, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY JUNIPER NETWORKS 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 JUNIPER NETWORKS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#if __FreeBSD_version > 800032
#define FILEMON_HAS_LINKAT
#endif
#if __FreeBSD_version < 900044 /* r225617 (2011-09-16) failed to bump
__FreeBSD_version. This really should
be based on "900045". "900044" is r225469
(2011-09-10) so this code is broken for
9-CURRENT September 10th-16th. */
#define sys_chdir chdir
#define sys_execve execve
#define sys_fork fork
#define sys_link link
#define sys_open open
#define sys_rename rename
#define sys_stat stat
#define sys_symlink symlink
#define sys_unlink unlink
#define sys_vfork vfork
#define sys_sys_exit sys_exit
#ifdef FILEMON_HAS_LINKAT
#define sys_linkat linkat
#endif
#endif /* __FreeBSD_version */
static void
filemon_output(struct filemon *filemon, char *msg, size_t len)
{
struct uio auio;
struct iovec aiov;
if (filemon->fp == NULL)
return;
aiov.iov_base = msg;
aiov.iov_len = len;
auio.uio_iov = &aiov;
auio.uio_iovcnt = 1;
auio.uio_resid = len;
auio.uio_segflg = UIO_SYSSPACE;
auio.uio_rw = UIO_WRITE;
auio.uio_td = curthread;
auio.uio_offset = (off_t) -1;
bwillwrite();
fo_write(filemon->fp, &auio, curthread->td_ucred, 0, curthread);
}
static struct filemon *
filemon_pid_check(struct proc *p)
{
struct filemon *filemon;
TAILQ_FOREACH(filemon, &filemons_inuse, link) {
if (p->p_pid == filemon->pid)
return (filemon);
}
if (p->p_pptr == NULL)
return (NULL);
return (filemon_pid_check(p->p_pptr));
}
static void
filemon_comment(struct filemon *filemon)
{
int len;
struct timeval now;
/* Load timestamp before locking. Less accurate but less contention. */
getmicrotime(&now);
/* Grab a read lock on the filemon inuse list. */
filemon_lock_read();
/* Lock the found filemon structure. */
filemon_filemon_lock(filemon);
len = snprintf(filemon->msgbufr, sizeof(filemon->msgbufr),
"# filemon version %d\n# Target pid %d\n# Start %ju.%06ju\nV %d\n",
FILEMON_VERSION, curproc->p_pid, (uintmax_t)now.tv_sec,
(uintmax_t)now.tv_usec, FILEMON_VERSION);
filemon_output(filemon, filemon->msgbufr, len);
/* Unlock the found filemon structure. */
filemon_filemon_unlock(filemon);
/* Release the read lock. */
filemon_unlock_read();
}
static int
filemon_wrapper_chdir(struct thread *td, struct chdir_args *uap)
{
int ret;
size_t done;
size_t len;
struct filemon *filemon;
if ((ret = sys_chdir(td, uap)) == 0) {
/* Grab a read lock on the filemon inuse list. */
filemon_lock_read();
if ((filemon = filemon_pid_check(curproc)) != NULL) {
/* Lock the found filemon structure. */
filemon_filemon_lock(filemon);
copyinstr(uap->path, filemon->fname1,
sizeof(filemon->fname1), &done);
len = snprintf(filemon->msgbufr,
sizeof(filemon->msgbufr), "C %d %s\n",
curproc->p_pid, filemon->fname1);
filemon_output(filemon, filemon->msgbufr, len);
/* Unlock the found filemon structure. */
filemon_filemon_unlock(filemon);
}
/* Release the read lock. */
filemon_unlock_read();
}
return (ret);
}
static int
filemon_wrapper_execve(struct thread *td, struct execve_args *uap)
{
char fname[MAXPATHLEN];
int ret;
size_t done;
size_t len;
struct filemon *filemon;
copyinstr(uap->fname, fname, sizeof(fname), &done);
if ((ret = sys_execve(td, uap)) == 0) {
/* Grab a read lock on the filemon inuse list. */
filemon_lock_read();
if ((filemon = filemon_pid_check(curproc)) != NULL) {
/* Lock the found filemon structure. */
filemon_filemon_lock(filemon);
len = snprintf(filemon->msgbufr,
sizeof(filemon->msgbufr), "E %d %s\n",
curproc->p_pid, fname);
filemon_output(filemon, filemon->msgbufr, len);
/* Unlock the found filemon structure. */
filemon_filemon_unlock(filemon);
}
/* Release the read lock. */
filemon_unlock_read();
}
return (ret);
}
#if defined(COMPAT_IA32) || defined(COMPAT_FREEBSD32) || defined(COMPAT_ARCH32)
static int
filemon_wrapper_freebsd32_execve(struct thread *td,
struct freebsd32_execve_args *uap)
{
char fname[MAXPATHLEN];
int ret;
size_t done;
size_t len;
struct filemon *filemon;
copyinstr(uap->fname, fname, sizeof(fname), &done);
if ((ret = freebsd32_execve(td, uap)) == 0) {
/* Grab a read lock on the filemon inuse list. */
filemon_lock_read();
if ((filemon = filemon_pid_check(curproc)) != NULL) {
/* Lock the found filemon structure. */
filemon_filemon_lock(filemon);
len = snprintf(filemon->msgbufr,
sizeof(filemon->msgbufr), "E %d %s\n",
curproc->p_pid, fname);
filemon_output(filemon, filemon->msgbufr, len);
/* Unlock the found filemon structure. */
filemon_filemon_unlock(filemon);
}
/* Release the read lock. */
filemon_unlock_read();
}
return (ret);
}
#endif
static int
filemon_wrapper_fork(struct thread *td, struct fork_args *uap)
{
int ret;
size_t len;
struct filemon *filemon;
if ((ret = sys_fork(td, uap)) == 0) {
/* Grab a read lock on the filemon inuse list. */
filemon_lock_read();
if ((filemon = filemon_pid_check(curproc)) != NULL) {
/* Lock the found filemon structure. */
filemon_filemon_lock(filemon);
len = snprintf(filemon->msgbufr,
sizeof(filemon->msgbufr), "F %d %ld\n",
curproc->p_pid, (long)curthread->td_retval[0]);
filemon_output(filemon, filemon->msgbufr, len);
/* Unlock the found filemon structure. */
filemon_filemon_unlock(filemon);
}
/* Release the read lock. */
filemon_unlock_read();
}
return (ret);
}
static int
filemon_wrapper_open(struct thread *td, struct open_args *uap)
{
int ret;
size_t done;
size_t len;
struct filemon *filemon;
if ((ret = sys_open(td, uap)) == 0) {
/* Grab a read lock on the filemon inuse list. */
filemon_lock_read();
if ((filemon = filemon_pid_check(curproc)) != NULL) {
/* Lock the found filemon structure. */
filemon_filemon_lock(filemon);
copyinstr(uap->path, filemon->fname1,
sizeof(filemon->fname1), &done);
if (uap->flags & O_RDWR) {
/*
* We'll get the W record below, but need
* to also output an R to distingish from
* O_WRONLY.
*/
len = snprintf(filemon->msgbufr,
sizeof(filemon->msgbufr), "R %d %s\n",
curproc->p_pid, filemon->fname1);
filemon_output(filemon, filemon->msgbufr, len);
}
len = snprintf(filemon->msgbufr,
sizeof(filemon->msgbufr), "%c %d %s\n",
(uap->flags & O_ACCMODE) ? 'W':'R',
curproc->p_pid, filemon->fname1);
filemon_output(filemon, filemon->msgbufr, len);
/* Unlock the found filemon structure. */
filemon_filemon_unlock(filemon);
}
/* Release the read lock. */
filemon_unlock_read();
}
return (ret);
}
static int
filemon_wrapper_rename(struct thread *td, struct rename_args *uap)
{
int ret;
size_t done;
size_t len;
struct filemon *filemon;
if ((ret = sys_rename(td, uap)) == 0) {
/* Grab a read lock on the filemon inuse list. */
filemon_lock_read();
if ((filemon = filemon_pid_check(curproc)) != NULL) {
/* Lock the found filemon structure. */
filemon_filemon_lock(filemon);
copyinstr(uap->from, filemon->fname1,
sizeof(filemon->fname1), &done);
copyinstr(uap->to, filemon->fname2,
sizeof(filemon->fname2), &done);
len = snprintf(filemon->msgbufr,
sizeof(filemon->msgbufr), "M %d '%s' '%s'\n",
curproc->p_pid, filemon->fname1, filemon->fname2);
filemon_output(filemon, filemon->msgbufr, len);
/* Unlock the found filemon structure. */
filemon_filemon_unlock(filemon);
}
/* Release the read lock. */
filemon_unlock_read();
}
return (ret);
}
static int
filemon_wrapper_link(struct thread *td, struct link_args *uap)
{
int ret;
size_t done;
size_t len;
struct filemon *filemon;
if ((ret = sys_link(td, uap)) == 0) {
/* Grab a read lock on the filemon inuse list. */
filemon_lock_read();
if ((filemon = filemon_pid_check(curproc)) != NULL) {
/* Lock the found filemon structure. */
filemon_filemon_lock(filemon);
copyinstr(uap->path, filemon->fname1,
sizeof(filemon->fname1), &done);
copyinstr(uap->link, filemon->fname2,
sizeof(filemon->fname2), &done);
len = snprintf(filemon->msgbufr,
sizeof(filemon->msgbufr), "L %d '%s' '%s'\n",
curproc->p_pid, filemon->fname1, filemon->fname2);
filemon_output(filemon, filemon->msgbufr, len);
/* Unlock the found filemon structure. */
filemon_filemon_unlock(filemon);
}
/* Release the read lock. */
filemon_unlock_read();
}
return (ret);
}
static int
filemon_wrapper_symlink(struct thread *td, struct symlink_args *uap)
{
int ret;
size_t done;
size_t len;
struct filemon *filemon;
if ((ret = sys_symlink(td, uap)) == 0) {
/* Grab a read lock on the filemon inuse list. */
filemon_lock_read();
if ((filemon = filemon_pid_check(curproc)) != NULL) {
/* Lock the found filemon structure. */
filemon_filemon_lock(filemon);
copyinstr(uap->path, filemon->fname1,
sizeof(filemon->fname1), &done);
copyinstr(uap->link, filemon->fname2,
sizeof(filemon->fname2), &done);
len = snprintf(filemon->msgbufr,
sizeof(filemon->msgbufr), "L %d '%s' '%s'\n",
curproc->p_pid, filemon->fname1, filemon->fname2);
filemon_output(filemon, filemon->msgbufr, len);
/* Unlock the found filemon structure. */
filemon_filemon_unlock(filemon);
}
/* Release the read lock. */
filemon_unlock_read();
}
return (ret);
}
#ifdef FILEMON_HAS_LINKAT
static int
filemon_wrapper_linkat(struct thread *td, struct linkat_args *uap)
{
int ret;
size_t done;
size_t len;
struct filemon *filemon;
if ((ret = sys_linkat(td, uap)) == 0) {
/* Grab a read lock on the filemon inuse list. */
filemon_lock_read();
if ((filemon = filemon_pid_check(curproc)) != NULL) {
/* Lock the found filemon structure. */
filemon_filemon_lock(filemon);
copyinstr(uap->path1, filemon->fname1,
sizeof(filemon->fname1), &done);
copyinstr(uap->path2, filemon->fname2,
sizeof(filemon->fname2), &done);
len = snprintf(filemon->msgbufr,
sizeof(filemon->msgbufr), "L %d '%s' '%s'\n",
curproc->p_pid, filemon->fname1, filemon->fname2);
filemon_output(filemon, filemon->msgbufr, len);
/* Unlock the found filemon structure. */
filemon_filemon_unlock(filemon);
}
/* Release the read lock. */
filemon_unlock_read();
}
return (ret);
}
#endif
static int
filemon_wrapper_stat(struct thread *td, struct stat_args *uap)
{
int ret;
size_t done;
size_t len;
struct filemon *filemon;
if ((ret = sys_stat(td, uap)) == 0) {
/* Grab a read lock on the filemon inuse list. */
filemon_lock_read();
if ((filemon = filemon_pid_check(curproc)) != NULL) {
/* Lock the found filemon structure. */
filemon_filemon_lock(filemon);
copyinstr(uap->path, filemon->fname1,
sizeof(filemon->fname1), &done);
len = snprintf(filemon->msgbufr,
sizeof(filemon->msgbufr), "S %d %s\n",
curproc->p_pid, filemon->fname1);
filemon_output(filemon, filemon->msgbufr, len);
/* Unlock the found filemon structure. */
filemon_filemon_unlock(filemon);
}
/* Release the read lock. */
filemon_unlock_read();
}
return (ret);
}
#if defined(COMPAT_IA32) || defined(COMPAT_FREEBSD32) || defined(COMPAT_ARCH32)
static int
filemon_wrapper_freebsd32_stat(struct thread *td,
struct freebsd32_stat_args *uap)
{
int ret;
size_t done;
size_t len;
struct filemon *filemon;
if ((ret = freebsd32_stat(td, uap)) == 0) {
/* Grab a read lock on the filemon inuse list. */
filemon_lock_read();
if ((filemon = filemon_pid_check(curproc)) != NULL) {
/* Lock the found filemon structure. */
filemon_filemon_lock(filemon);
copyinstr(uap->path, filemon->fname1,
sizeof(filemon->fname1), &done);
len = snprintf(filemon->msgbufr,
sizeof(filemon->msgbufr), "S %d %s\n",
curproc->p_pid, filemon->fname1);
filemon_output(filemon, filemon->msgbufr, len);
/* Unlock the found filemon structure. */
filemon_filemon_unlock(filemon);
}
/* Release the read lock. */
filemon_unlock_read();
}
return (ret);
}
#endif
static void
filemon_wrapper_sys_exit(struct thread *td, struct sys_exit_args *uap)
{
size_t len;
struct filemon *filemon;
struct timeval now;
/* Get timestamp before locking. */
getmicrotime(&now);
/* Grab a read lock on the filemon inuse list. */
filemon_lock_read();
if ((filemon = filemon_pid_check(curproc)) != NULL) {
/* Lock the found filemon structure. */
filemon_filemon_lock(filemon);
len = snprintf(filemon->msgbufr, sizeof(filemon->msgbufr),
"X %d %d\n", curproc->p_pid, uap->rval);
filemon_output(filemon, filemon->msgbufr, len);
/* Check if the monitored process is about to exit. */
if (filemon->pid == curproc->p_pid) {
len = snprintf(filemon->msgbufr,
sizeof(filemon->msgbufr),
"# Stop %ju.%06ju\n# Bye bye\n",
(uintmax_t)now.tv_sec, (uintmax_t)now.tv_usec);
filemon_output(filemon, filemon->msgbufr, len);
}
/* Unlock the found filemon structure. */
filemon_filemon_unlock(filemon);
}
/* Release the read lock. */
filemon_unlock_read();
sys_sys_exit(td, uap);
}
static int
filemon_wrapper_unlink(struct thread *td, struct unlink_args *uap)
{
int ret;
size_t done;
size_t len;
struct filemon *filemon;
if ((ret = sys_unlink(td, uap)) == 0) {
/* Grab a read lock on the filemon inuse list. */
filemon_lock_read();
if ((filemon = filemon_pid_check(curproc)) != NULL) {
/* Lock the found filemon structure. */
filemon_filemon_lock(filemon);
copyinstr(uap->path, filemon->fname1,
sizeof(filemon->fname1), &done);
len = snprintf(filemon->msgbufr,
sizeof(filemon->msgbufr), "D %d %s\n",
curproc->p_pid, filemon->fname1);
filemon_output(filemon, filemon->msgbufr, len);
/* Unlock the found filemon structure. */
filemon_filemon_unlock(filemon);
}
/* Release the read lock. */
filemon_unlock_read();
}
return (ret);
}
static int
filemon_wrapper_vfork(struct thread *td, struct vfork_args *uap)
{
int ret;
size_t len;
struct filemon *filemon;
if ((ret = sys_vfork(td, uap)) == 0) {
/* Grab a read lock on the filemon inuse list. */
filemon_lock_read();
if ((filemon = filemon_pid_check(curproc)) != NULL) {
/* Lock the found filemon structure. */
filemon_filemon_lock(filemon);
len = snprintf(filemon->msgbufr,
sizeof(filemon->msgbufr), "F %d %ld\n",
curproc->p_pid, (long)curthread->td_retval[0]);
filemon_output(filemon, filemon->msgbufr, len);
/* Unlock the found filemon structure. */
filemon_filemon_unlock(filemon);
}
/* Release the read lock. */
filemon_unlock_read();
}
return (ret);
}
static void
filemon_wrapper_install(void)
{
#if defined(__i386__)
struct sysent *sv_table = elf32_freebsd_sysvec.sv_table;
#elif defined(__amd64__)
struct sysent *sv_table = elf64_freebsd_sysvec.sv_table;
#else
#error Machine type not supported
#endif
sv_table[SYS_chdir].sy_call = (sy_call_t *) filemon_wrapper_chdir;
sv_table[SYS_exit].sy_call = (sy_call_t *) filemon_wrapper_sys_exit;
sv_table[SYS_execve].sy_call = (sy_call_t *) filemon_wrapper_execve;
sv_table[SYS_fork].sy_call = (sy_call_t *) filemon_wrapper_fork;
sv_table[SYS_open].sy_call = (sy_call_t *) filemon_wrapper_open;
sv_table[SYS_rename].sy_call = (sy_call_t *) filemon_wrapper_rename;
sv_table[SYS_stat].sy_call = (sy_call_t *) filemon_wrapper_stat;
sv_table[SYS_unlink].sy_call = (sy_call_t *) filemon_wrapper_unlink;
sv_table[SYS_vfork].sy_call = (sy_call_t *) filemon_wrapper_vfork;
sv_table[SYS_link].sy_call = (sy_call_t *) filemon_wrapper_link;
sv_table[SYS_symlink].sy_call = (sy_call_t *) filemon_wrapper_symlink;
#ifdef FILEMON_HAS_LINKAT
sv_table[SYS_linkat].sy_call = (sy_call_t *) filemon_wrapper_linkat;
#endif
#if defined(COMPAT_IA32) || defined(COMPAT_FREEBSD32) || defined(COMPAT_ARCH32)
sv_table = ia32_freebsd_sysvec.sv_table;
sv_table[FREEBSD32_SYS_chdir].sy_call = (sy_call_t *) filemon_wrapper_chdir;
sv_table[FREEBSD32_SYS_exit].sy_call = (sy_call_t *) filemon_wrapper_sys_exit;
sv_table[FREEBSD32_SYS_freebsd32_execve].sy_call = (sy_call_t *) filemon_wrapper_freebsd32_execve;
sv_table[FREEBSD32_SYS_fork].sy_call = (sy_call_t *) filemon_wrapper_fork;
sv_table[FREEBSD32_SYS_open].sy_call = (sy_call_t *) filemon_wrapper_open;
sv_table[FREEBSD32_SYS_rename].sy_call = (sy_call_t *) filemon_wrapper_rename;
sv_table[FREEBSD32_SYS_freebsd32_stat].sy_call = (sy_call_t *) filemon_wrapper_freebsd32_stat;
sv_table[FREEBSD32_SYS_unlink].sy_call = (sy_call_t *) filemon_wrapper_unlink;
sv_table[FREEBSD32_SYS_vfork].sy_call = (sy_call_t *) filemon_wrapper_vfork;
sv_table[FREEBSD32_SYS_link].sy_call = (sy_call_t *) filemon_wrapper_link;
sv_table[FREEBSD32_SYS_symlink].sy_call = (sy_call_t *) filemon_wrapper_symlink;
#ifdef FILEMON_HAS_LINKAT
sv_table[FREEBSD32_SYS_linkat].sy_call = (sy_call_t *) filemon_wrapper_linkat;
#endif
#endif /* COMPAT_ARCH32 */
}
static void
filemon_wrapper_deinstall(void)
{
#if defined(__i386__)
struct sysent *sv_table = elf32_freebsd_sysvec.sv_table;
#elif defined(__amd64__)
struct sysent *sv_table = elf64_freebsd_sysvec.sv_table;
#else
#error Machine type not supported
#endif
sv_table[SYS_chdir].sy_call = (sy_call_t *)sys_chdir;
sv_table[SYS_exit].sy_call = (sy_call_t *)sys_sys_exit;
sv_table[SYS_execve].sy_call = (sy_call_t *)sys_execve;
sv_table[SYS_fork].sy_call = (sy_call_t *)sys_fork;
sv_table[SYS_open].sy_call = (sy_call_t *)sys_open;
sv_table[SYS_rename].sy_call = (sy_call_t *)sys_rename;
sv_table[SYS_stat].sy_call = (sy_call_t *)sys_stat;
sv_table[SYS_unlink].sy_call = (sy_call_t *)sys_unlink;
sv_table[SYS_vfork].sy_call = (sy_call_t *)sys_vfork;
sv_table[SYS_link].sy_call = (sy_call_t *)sys_link;
sv_table[SYS_symlink].sy_call = (sy_call_t *)sys_symlink;
#ifdef FILEMON_HAS_LINKAT
sv_table[SYS_linkat].sy_call = (sy_call_t *)sys_linkat;
#endif
#if defined(COMPAT_IA32) || defined(COMPAT_FREEBSD32) || defined(COMPAT_ARCH32)
sv_table = ia32_freebsd_sysvec.sv_table;
sv_table[FREEBSD32_SYS_chdir].sy_call = (sy_call_t *)sys_chdir;
sv_table[FREEBSD32_SYS_exit].sy_call = (sy_call_t *)sys_sys_exit;
sv_table[FREEBSD32_SYS_freebsd32_execve].sy_call = (sy_call_t *)freebsd32_execve;
sv_table[FREEBSD32_SYS_fork].sy_call = (sy_call_t *)sys_fork;
sv_table[FREEBSD32_SYS_open].sy_call = (sy_call_t *)sys_open;
sv_table[FREEBSD32_SYS_rename].sy_call = (sy_call_t *)sys_rename;
sv_table[FREEBSD32_SYS_freebsd32_stat].sy_call = (sy_call_t *)freebsd32_stat;
sv_table[FREEBSD32_SYS_unlink].sy_call = (sy_call_t *)sys_unlink;
sv_table[FREEBSD32_SYS_vfork].sy_call = (sy_call_t *)sys_vfork;
sv_table[FREEBSD32_SYS_link].sy_call = (sy_call_t *)sys_link;
sv_table[FREEBSD32_SYS_symlink].sy_call = (sy_call_t *)sys_symlink;
#ifdef FILEMON_HAS_LINKAT
sv_table[FREEBSD32_SYS_linkat].sy_call = (sy_call_t *)sys_linkat;
#endif
#endif /* COMPAT_ARCH32 */
}

View File

@ -105,6 +105,7 @@ SUBDIR= ${_3dfx} \
fdc \
fdescfs \
${_fe} \
${_filemon} \
firewire \
firmware \
${_fxp} \
@ -359,6 +360,7 @@ SUBDIR= ${_3dfx} \
.if ${MACHINE_CPUARCH} != "powerpc" && ${MACHINE_CPUARCH} != "arm" && \
${MACHINE_CPUARCH} != "mips"
_filemon= filemon
_syscons= syscons
_vpo= vpo
.endif

View File

@ -0,0 +1,11 @@
# $FreeBSD$
MAINTAINER= obrien@FreeBSD.org
.PATH: ${.CURDIR}/../../dev/filemon
KMOD= filemon
SRCS= ${KMOD}.c
SRCS+= vnode_if.h opt_compat.h opt_capsicum.h
.include <bsd.kmod.mk>