Index: stable/10/share/man/man4/filemon.4 =================================================================== --- stable/10/share/man/man4/filemon.4 (revision 296014) +++ stable/10/share/man/man4/filemon.4 (revision 296015) @@ -1,174 +1,195 @@ .\" Copyright (c) 2012 .\" David E. O'Brien . 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 acknowledgment: .\" This product includes software developed by David E. O'Brien and .\" contributors. .\" 4. Neither the name of the author 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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANT ABILITY 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$ .\" -.Dd June 14, 2013 +.Dd January 28, 2016 .Dt FILEMON 4 .Os .Sh NAME .Nm filemon .Nd the filemon device .Sh SYNOPSIS .In dev/filemon/filemon.h .Sh DESCRIPTION The .Nm device allows a process to collect file operations data of its children. The device .Pa /dev/filemon responds to two .Xr ioctl 2 calls. .Pp +.Nm +is not intended to be a security auditing tool. +Many syscalls are not tracked and binaries of foreign ABI will not be fully +audited. +It is intended for auditing of processes for the purpose of determining its +dependencies in an efficient and easily parsable format. +An example of this is +.Xr make 1 +which uses this module with +.Sy .MAKE.MODE=meta +to handle incremental builds more smartly. +.Pp System calls are denoted using the following single letters: .Pp .Bl -tag -width indent -compact .It Ql C .Xr chdir 2 .It Ql D .Xr unlink 2 .It Ql E .Xr exec 2 .It Ql F .Xr fork 2 , .Xr vfork 2 .It Ql L .Xr link 2 , .Xr linkat 2 , .Xr symlink 2 , .Xr symlinkat 2 .It Ql M .Xr rename 2 .It Ql R .Xr open 2 for read .It Ql S .Xr stat 2 .It Ql W .Xr open 2 for write .It Ql X .Xr _exit 2 .El .Pp Note that .Ql R following .Ql W records can represent a single .Xr open 2 for R/W, or two separate .Xr open 2 calls, one for .Ql R and one for .Ql W . Note that only successful system calls are captured. .Sh IOCTLS User mode programs communicate with the .Nm driver through a number of ioctls which are described below. Each takes a single argument. .Bl -tag -width ".Dv FILEMON_SET_PID" .It Dv FILEMON_SET_FD Write the internal tracing buffer to the supplied open file descriptor. .It Dv FILEMON_SET_PID Child process ID to trace. .El .Sh RETURN VALUES .\" .Rv -std ioctl The .Fn ioctl function returns the value 0 if successful; otherwise the value \-1 is returned and the global variable .Va errno is set to indicate the error. .Sh FILES .Bl -tag -width ".Pa /dev/filemon" .It Pa /dev/filemon .El .Sh EXAMPLES .Bd -literal #include #include #include #include #include #include #include #include static void open_filemon(void) { pid_t child; int fm_fd, fm_log; if ((fm_fd = open("/dev/filemon", O_RDWR | O_CLOEXEC)) == -1) err(1, "open(\e"/dev/filemon\e", O_RDWR)"); if ((fm_log = open("filemon.out", O_CREAT | O_WRONLY | O_TRUNC | O_CLOEXEC, DEFFILEMODE)) == -1) err(1, "open(filemon.out)"); if (ioctl(fm_fd, FILEMON_SET_FD, &fm_log) == -1) err(1, "Cannot set filemon log file descriptor"); if ((child = fork()) == 0) { child = getpid(); if (ioctl(fm_fd, FILEMON_SET_PID, &child) == -1) err(1, "Cannot set filemon PID"); /* Do something here. */ } else { wait(&child); close(fm_fd); } } .Ed .Pp Creates a file named .Pa filemon.out and configures the .Nm device to write the .Nm buffer contents to it. .Sh SEE ALSO .Xr dtrace 1 , .Xr ktrace 1 , .Xr truss 1 , .Xr ioctl 2 .Sh HISTORY A .Nm device appeared in .Fx 9.1 . +.Sh BUGS +Loading +.Nm +may reduce system performance for the noted syscalls. +.Pp +Only children of the set process are logged. +Processes can escape being traced by double forking. +This is not seen as a problem as the intended use is build monitoring, which +does not make sense to have daemons for. Index: stable/10/sys/dev/filemon/filemon.c =================================================================== --- stable/10/sys/dev/filemon/filemon.c (revision 296014) +++ stable/10/sys/dev/filemon/filemon.c (revision 296015) @@ -1,300 +1,324 @@ /*- * Copyright (c) 2011, David E. O'Brien. * Copyright (c) 2009-2011, Juniper Networks, Inc. * Copyright (c) 2015, EMC Corp. * 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 __FBSDID("$FreeBSD$"); #include "opt_compat.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if __FreeBSD_version >= 900041 #include #endif #include "filemon.h" #if defined(COMPAT_IA32) || defined(COMPAT_FREEBSD32) || defined(COMPAT_ARCH32) #include #include 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 sx lock; /* Lock mutex for this filemon. */ struct file *fp; /* Output file pointer. */ - pid_t pid; /* The process ID being monitored. */ + struct proc *p; /* The process 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 struct sx access_lock; static struct cdev *filemon_dev; #include "filemon_lock.c" #include "filemon_wrapper.c" static void +filemon_comment(struct filemon *filemon) +{ + int len; + struct timeval now; + + getmicrotime(&now); + + 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); +} + +static void filemon_dtr(void *data) { struct filemon *filemon = data; if (filemon != NULL) { - struct file *fp = filemon->fp; + struct file *fp; - /* Get exclusive write access. */ + /* Follow same locking order as filemon_pid_check. */ filemon_lock_write(); + filemon_filemon_lock(filemon); /* Remove from the in-use list. */ TAILQ_REMOVE(&filemons_inuse, filemon, link); + fp = filemon->fp; filemon->fp = NULL; - filemon->pid = -1; + filemon->p = NULL; /* Add to the free list. */ TAILQ_INSERT_TAIL(&filemons_free, filemon, link); /* Give up write access. */ + filemon_filemon_unlock(filemon); 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; struct proc *p; #if __FreeBSD_version >= 900041 cap_rights_t rights; #endif - devfs_get_cdevpriv((void **) &filemon); + if ((error = devfs_get_cdevpriv((void **) &filemon)) != 0) + return (error); + filemon_filemon_lock(filemon); + switch (cmd) { /* Set the output file descriptor. */ case FILEMON_SET_FD: + if (filemon->fp != NULL) + fdrop(filemon->fp, td); + error = fget_write(td, *(int *)data, #if __FreeBSD_version >= 900041 cap_rights_init(&rights, CAP_PWRITE), #endif &filemon->fp); if (error == 0) /* Write the file header. */ filemon_comment(filemon); break; /* Set the monitored process ID. */ case FILEMON_SET_PID: error = pget(*((pid_t *)data), PGET_CANDEBUG | PGET_NOTWEXIT, &p); if (error == 0) { - filemon->pid = p->p_pid; + filemon->p = p; PROC_UNLOCK(p); } break; default: error = EINVAL; break; } + filemon_filemon_unlock(filemon); 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); sx_init(&filemon->lock, "filemon"); } - - filemon->pid = curproc->p_pid; devfs_set_cdevpriv(filemon, filemon_dtr); /* 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) { return (0); } static void filemon_load(void *dummy __unused) { sx_init(&access_lock, "filemons_inuse"); /* Install the syscall wrappers. */ filemon_wrapper_install(); filemon_dev = make_dev(&filemon_cdevsw, 0, UID_ROOT, GID_WHEEL, 0666, "filemon"); } 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 { destroy_dev(filemon_dev); /* Deinstall the syscall wrappers. */ filemon_wrapper_deinstall(); } /* Give up write access. */ filemon_unlock_write(); if (error == 0) { /* free() filemon structs free list. */ filemon_lock_write(); while ((filemon = TAILQ_FIRST(&filemons_free)) != NULL) { TAILQ_REMOVE(&filemons_free, filemon, link); sx_destroy(&filemon->lock); free(filemon, M_FILEMON); } filemon_unlock_write(); sx_destroy(&access_lock); } 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); Index: stable/10/sys/dev/filemon/filemon_wrapper.c =================================================================== --- stable/10/sys/dev/filemon/filemon_wrapper.c (revision 296014) +++ stable/10/sys/dev/filemon/filemon_wrapper.c (revision 296015) @@ -1,684 +1,601 @@ /*- * Copyright (c) 2011, David E. O'Brien. * Copyright (c) 2009-2011, Juniper Networks, Inc. * Copyright (c) 2015, EMC Corp. * 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 __FBSDID("$FreeBSD$"); +#include +#include #include +#include #include "opt_compat.h" #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 eventhandler_tag filemon_exec_tag; +static eventhandler_tag filemon_exit_tag; +static eventhandler_tag filemon_fork_tag; + 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; filemon_lock_read(); if (TAILQ_EMPTY(&filemons_inuse)) { filemon_unlock_read(); return (NULL); } sx_slock(&proctree_lock); - while (p != initproc) { + while (p->p_pid != 0) { TAILQ_FOREACH(filemon, &filemons_inuse, link) { - if (p->p_pid == filemon->pid) { + if (p == filemon->p) { sx_sunlock(&proctree_lock); filemon_filemon_lock(filemon); filemon_unlock_read(); return (filemon); } } p = proc_realparent(p); } sx_sunlock(&proctree_lock); filemon_unlock_read(); return (NULL); } -static void -filemon_comment(struct filemon *filemon) -{ - int len; - struct timeval now; - - /* Load timestamp before locking. Less accurate but less contention. */ - getmicrotime(&now); - - /* 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); -} - 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) { if ((filemon = filemon_pid_check(curproc)) != NULL) { 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); } } return (ret); } -static int -filemon_wrapper_execve(struct thread *td, struct execve_args *uap) +static void +filemon_event_process_exec(void *arg __unused, struct proc *p, + struct image_params *imgp) { - 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) { - if ((filemon = filemon_pid_check(curproc)) != NULL) { - 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); - } - } - - 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; + char *fullpath, *freepath; size_t len; - struct filemon *filemon; - copyinstr(uap->fname, fname, sizeof(fname), &done); + if ((filemon = filemon_pid_check(p)) != NULL) { + fullpath = ""; + freepath = NULL; - if ((ret = freebsd32_execve(td, uap)) == 0) { - if ((filemon = filemon_pid_check(curproc)) != NULL) { - len = snprintf(filemon->msgbufr, - sizeof(filemon->msgbufr), "E %d %s\n", - curproc->p_pid, fname); + vn_fullpath(FIRST_THREAD_IN_PROC(p), imgp->vp, &fullpath, + &freepath); - filemon_output(filemon, filemon->msgbufr, len); + len = snprintf(filemon->msgbufr, + sizeof(filemon->msgbufr), "E %d %s\n", + p->p_pid, fullpath); - /* Unlock the found filemon structure. */ - filemon_filemon_unlock(filemon); - } - } + filemon_output(filemon, filemon->msgbufr, len); - return (ret); -} -#endif + /* Unlock the found filemon structure. */ + filemon_filemon_unlock(filemon); -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) { - if ((filemon = filemon_pid_check(curproc)) != NULL) { - 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); - } + free(freepath, M_TEMP); } - - 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) { if ((filemon = filemon_pid_check(curproc)) != NULL) { 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); } } return (ret); } static int filemon_wrapper_openat(struct thread *td, struct openat_args *uap) { int ret; size_t done; size_t len; struct filemon *filemon; if ((ret = sys_openat(td, uap)) == 0) { if ((filemon = filemon_pid_check(curproc)) != NULL) { copyinstr(uap->path, filemon->fname1, sizeof(filemon->fname1), &done); filemon->fname2[0] = '\0'; if (filemon->fname1[0] != '/' && uap->fd != AT_FDCWD) { /* * rats - we cannot do too much about this. * the trace should show a dir we read * recently.. output an A record as a clue * until we can do better. */ len = snprintf(filemon->msgbufr, sizeof(filemon->msgbufr), "A %d %s\n", curproc->p_pid, filemon->fname1); filemon_output(filemon, filemon->msgbufr, len); } if (uap->flag & 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%s\n", curproc->p_pid, filemon->fname2, filemon->fname1); filemon_output(filemon, filemon->msgbufr, len); } len = snprintf(filemon->msgbufr, sizeof(filemon->msgbufr), "%c %d %s%s\n", (uap->flag & O_ACCMODE) ? 'W':'R', curproc->p_pid, filemon->fname2, filemon->fname1); filemon_output(filemon, filemon->msgbufr, len); /* Unlock the found filemon structure. */ filemon_filemon_unlock(filemon); } } 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) { if ((filemon = filemon_pid_check(curproc)) != NULL) { 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); } } 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) { if ((filemon = filemon_pid_check(curproc)) != NULL) { 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); } } 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) { if ((filemon = filemon_pid_check(curproc)) != NULL) { 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); } } 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) { if ((filemon = filemon_pid_check(curproc)) != NULL) { 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); } } 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) { if ((filemon = filemon_pid_check(curproc)) != NULL) { 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); } } 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) { if ((filemon = filemon_pid_check(curproc)) != NULL) { 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); } } return (ret); } #endif static void -filemon_wrapper_sys_exit(struct thread *td, struct sys_exit_args *uap) +filemon_event_process_exit(void *arg __unused, struct proc *p) { size_t len; struct filemon *filemon; struct timeval now; /* Get timestamp before locking. */ getmicrotime(&now); - if ((filemon = filemon_pid_check(curproc)) != NULL) { + if ((filemon = filemon_pid_check(p)) != NULL) { len = snprintf(filemon->msgbufr, sizeof(filemon->msgbufr), - "X %d %d\n", curproc->p_pid, uap->rval); + "X %d %d\n", p->p_pid, W_EXITCODE(p->p_xstat, 0)); filemon_output(filemon, filemon->msgbufr, len); /* Check if the monitored process is about to exit. */ - if (filemon->pid == curproc->p_pid) { + if (filemon->p == p) { 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); - filemon->pid = -1; + filemon->p = NULL; } /* Unlock the found filemon structure. */ filemon_filemon_unlock(filemon); } - - 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) { if ((filemon = filemon_pid_check(curproc)) != NULL) { 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); } } return (ret); } -static int -filemon_wrapper_vfork(struct thread *td, struct vfork_args *uap) +static void +filemon_event_process_fork(void *arg __unused, struct proc *p1, + struct proc *p2, int flags __unused) { - int ret; size_t len; struct filemon *filemon; - if ((ret = sys_vfork(td, uap)) == 0) { - if ((filemon = filemon_pid_check(curproc)) != NULL) { - len = snprintf(filemon->msgbufr, - sizeof(filemon->msgbufr), "F %d %ld\n", - curproc->p_pid, (long)curthread->td_retval[0]); + if ((filemon = filemon_pid_check(p1)) != NULL) { + len = snprintf(filemon->msgbufr, + sizeof(filemon->msgbufr), "F %d %d\n", + p1->p_pid, p2->p_pid); - filemon_output(filemon, filemon->msgbufr, len); + filemon_output(filemon, filemon->msgbufr, len); - /* Unlock the found filemon structure. */ - filemon_filemon_unlock(filemon); - } + /* Unlock the found filemon structure. */ + filemon_filemon_unlock(filemon); } - - return (ret); } static void filemon_wrapper_install(void) { #if defined(__LP64__) struct sysent *sv_table = elf64_freebsd_sysvec.sv_table; #else struct sysent *sv_table = elf32_freebsd_sysvec.sv_table; #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_openat].sy_call = (sy_call_t *) filemon_wrapper_openat; 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_openat].sy_call = (sy_call_t *) filemon_wrapper_openat; 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 */ + + filemon_exec_tag = EVENTHANDLER_REGISTER(process_exec, + filemon_event_process_exec, NULL, EVENTHANDLER_PRI_LAST); + filemon_exit_tag = EVENTHANDLER_REGISTER(process_exit, + filemon_event_process_exit, NULL, EVENTHANDLER_PRI_LAST); + filemon_fork_tag = EVENTHANDLER_REGISTER(process_fork, + filemon_event_process_fork, NULL, EVENTHANDLER_PRI_LAST); } static void filemon_wrapper_deinstall(void) { #if defined(__LP64__) struct sysent *sv_table = elf64_freebsd_sysvec.sv_table; #else struct sysent *sv_table = elf32_freebsd_sysvec.sv_table; #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_openat].sy_call = (sy_call_t *)sys_openat; 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_openat].sy_call = (sy_call_t *)sys_openat; 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 */ + + EVENTHANDLER_DEREGISTER(process_exec, filemon_exec_tag); + EVENTHANDLER_DEREGISTER(process_exit, filemon_exit_tag); + EVENTHANDLER_DEREGISTER(process_fork, filemon_fork_tag); } Index: stable/10/sys/modules/filemon/Makefile =================================================================== --- stable/10/sys/modules/filemon/Makefile (revision 296014) +++ stable/10/sys/modules/filemon/Makefile (revision 296015) @@ -1,9 +1,9 @@ # $FreeBSD$ .PATH: ${.CURDIR}/../../dev/filemon KMOD= filemon SRCS= ${KMOD}.c -SRCS+= opt_compat.h +SRCS+= opt_compat.h vnode_if.h .include Index: stable/10 =================================================================== --- stable/10 (revision 296014) +++ stable/10 (revision 296015) Property changes on: stable/10 ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head:r294933,294949,294952-294953,294957,294965,294967-294968,295017,295026-295027,295029-295030,295649