aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--share/man/man4/filemon.429
-rw-r--r--sys/dev/filemon/filemon.c321
-rw-r--r--sys/dev/filemon/filemon_lock.c57
-rw-r--r--sys/dev/filemon/filemon_wrapper.c127
-rw-r--r--sys/sys/param.h2
-rw-r--r--sys/sys/proc.h2
6 files changed, 315 insertions, 223 deletions
diff --git a/share/man/man4/filemon.4 b/share/man/man4/filemon.4
index 3287a47aab6a..75b4fcf2a83d 100644
--- a/share/man/man4/filemon.4
+++ b/share/man/man4/filemon.4
@@ -31,7 +31,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd March 9, 2016
+.Dd March 21, 2016
.Dt FILEMON 4
.Os
.Sh NAME
@@ -116,6 +116,10 @@ Each takes a single argument.
Write the internal tracing buffer to the supplied open file descriptor.
.It Dv FILEMON_SET_PID
Child process ID to trace.
+This should normally be done under the control of a parent in the child after
+.Xr fork 2
+but before anything else.
+See the example below.
.El
.Sh RETURN VALUES
.\" .Rv -std ioctl
@@ -138,6 +142,20 @@ The
.Nm
handle is already associated with a file descriptor.
.El
+.Pp
+The
+.Fn ioctl
+system call
+with
+.Dv FILEMON_SET_PID
+will fail if:
+.Bl -tag -width Er
+.It Bq Er ESRCH
+No process having the specified process ID exists.
+.It Bq Er EBUSY
+The process ID specified is already being traced and was not the current
+process.
+.El
.Sh FILES
.Bl -tag -width ".Pa /dev/filemon"
.It Pa /dev/filemon
@@ -199,14 +217,5 @@ A
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.
-.Pp
Unloading the module may panic the system, thus requires using
.Ic kldunload -f .
diff --git a/sys/dev/filemon/filemon.c b/sys/dev/filemon/filemon.c
index cd40c5a2e329..3a472f6342fd 100644
--- a/sys/dev/filemon/filemon.c
+++ b/sys/dev/filemon/filemon.c
@@ -1,7 +1,7 @@
/*-
* Copyright (c) 2011, David E. O'Brien.
* Copyright (c) 2009-2011, Juniper Networks, Inc.
- * Copyright (c) 2015, EMC Corp.
+ * Copyright (c) 2015-2016, EMC Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -46,7 +46,6 @@ __FBSDID("$FreeBSD$");
#include <sys/module.h>
#include <sys/poll.h>
#include <sys/proc.h>
-#include <sys/queue.h>
#include <sys/sx.h>
#include <sys/syscall.h>
#include <sys/sysent.h>
@@ -80,23 +79,126 @@ static struct cdevsw filemon_cdevsw = {
MALLOC_DECLARE(M_FILEMON);
MALLOC_DEFINE(M_FILEMON, "filemon", "File access monitor");
+/*
+ * The filemon->lock protects several things currently:
+ * - fname1/fname2/msgbufr are pre-allocated and used per syscall
+ * for logging and copyins rather than stack variables.
+ * - Serializing the filemon's log output.
+ * - Preventing inheritance or removal of the filemon into proc.p_filemon.
+ */
struct filemon {
- TAILQ_ENTRY(filemon) link; /* Link into the in-use list. */
- struct sx lock; /* Lock mutex for this filemon. */
+ struct sx lock; /* Lock for this filemon. */
struct file *fp; /* Output file pointer. */
- 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. */
+ u_int refcnt; /* Pointer reference count. */
+ u_int proccnt; /* Process count. */
};
-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;
+static void filemon_output(struct filemon *filemon, char *msg, size_t len);
+
+static __inline struct filemon *
+filemon_acquire(struct filemon *filemon)
+{
+
+ if (filemon != NULL)
+ refcount_acquire(&filemon->refcnt);
+ return (filemon);
+}
+
+/*
+ * Release a reference and on the last one write the footer and free the
+ * filemon.
+ */
+static void
+filemon_release(struct filemon *filemon)
+{
+ size_t len;
+ struct timeval now;
+
+ if (refcount_release(&filemon->refcnt) == 0)
+ return;
+ /*
+ * There are valid cases of releasing while locked, such as in
+ * filemon_untrack_processes, but none which are done where there
+ * is not at least 1 reference remaining.
+ */
+ sx_assert(&filemon->lock, SA_UNLOCKED);
+
+ if (filemon->fp != NULL) {
+ getmicrotime(&now);
+
+ 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);
+ fdrop(filemon->fp, curthread);
+ }
+
+ sx_destroy(&filemon->lock);
+ free(filemon, M_FILEMON);
+}
+
+/*
+ * Acquire the proc's p_filemon reference and lock the filemon.
+ * The proc's p_filemon may not match this filemon on return.
+ */
+static struct filemon *
+filemon_proc_get(struct proc *p)
+{
+ struct filemon *filemon;
+
+ PROC_LOCK(p);
+ filemon = filemon_acquire(p->p_filemon);
+ PROC_UNLOCK(p);
+
+ if (filemon == NULL)
+ return (NULL);
+ /*
+ * The p->p_filemon may have changed by now. That case is handled
+ * by the exit and fork hooks and filemon_attach_proc specially.
+ */
+ sx_xlock(&filemon->lock);
+ return (filemon);
+}
+
+/* Remove and release the filemon on the given process. */
+static void
+filemon_proc_drop(struct proc *p)
+{
+ struct filemon *filemon;
+
+ KASSERT(p->p_filemon != NULL, ("%s: proc %p NULL p_filemon",
+ __func__, p));
+ sx_assert(&p->p_filemon->lock, SA_XLOCKED);
+ PROC_LOCK(p);
+ filemon = p->p_filemon;
+ p->p_filemon = NULL;
+ --filemon->proccnt;
+ PROC_UNLOCK(p);
+ /*
+ * This should not be the last reference yet. filemon_release()
+ * cannot be called with filemon locked, which the caller expects
+ * will stay locked.
+ */
+ KASSERT(filemon->refcnt > 1, ("%s: proc %p dropping filemon %p "
+ "with last reference", __func__, p, filemon));
+ filemon_release(filemon);
+}
+
+/* Unlock and release the filemon. */
+static __inline void
+filemon_drop(struct filemon *filemon)
+{
+
+ sx_xunlock(&filemon->lock);
+ filemon_release(filemon);
+}
-#include "filemon_lock.c"
#include "filemon_wrapper.c"
static void
@@ -115,35 +217,120 @@ filemon_comment(struct filemon *filemon)
filemon_output(filemon, filemon->msgbufr, len);
}
+/*
+ * Invalidate the passed filemon in all processes.
+ */
static void
-filemon_dtr(void *data)
+filemon_untrack_processes(struct filemon *filemon)
{
- struct filemon *filemon = data;
+ struct proc *p;
- if (filemon != NULL) {
- struct file *fp;
+ sx_assert(&filemon->lock, SA_XLOCKED);
- /* Follow same locking order as filemon_pid_check. */
- filemon_lock_write();
- sx_xlock(&filemon->lock);
+ /* Avoid allproc loop if there is no need. */
+ if (filemon->proccnt == 0)
+ return;
- /* Remove from the in-use list. */
- TAILQ_REMOVE(&filemons_inuse, filemon, link);
+ /*
+ * Processes in this list won't go away while here since
+ * filemon_event_process_exit() will lock on filemon->lock
+ * which we hold.
+ */
+ sx_slock(&allproc_lock);
+ FOREACH_PROC_IN_SYSTEM(p) {
+ /*
+ * No PROC_LOCK is needed to compare here since it is
+ * guaranteed to not change since we have its filemon
+ * locked. Everything that changes this p_filemon will
+ * be locked on it.
+ */
+ if (p->p_filemon == filemon)
+ filemon_proc_drop(p);
+ }
+ sx_sunlock(&allproc_lock);
+
+ /*
+ * It's possible some references were acquired but will be
+ * dropped shortly as they are restricted from being
+ * inherited. There is at least the reference in cdevpriv remaining.
+ */
+ KASSERT(filemon->refcnt > 0, ("%s: filemon %p should have "
+ "references still.", __func__, filemon));
+ KASSERT(filemon->proccnt == 0, ("%s: filemon %p should not have "
+ "attached procs still.", __func__, filemon));
+}
- fp = filemon->fp;
- filemon->fp = NULL;
- filemon->p = NULL;
- /* Add to the free list. */
- TAILQ_INSERT_TAIL(&filemons_free, filemon, link);
+/* The devfs file is being closed. Untrace all processes. */
+static void
+filemon_dtr(void *data)
+{
+ struct filemon *filemon = data;
- /* Give up write access. */
- sx_xunlock(&filemon->lock);
- filemon_unlock_write();
+ if (filemon == NULL)
+ return;
- if (fp != NULL)
- fdrop(fp, curthread);
+ sx_xlock(&filemon->lock);
+ /*
+ * Detach the filemon. The actual closing of it may not
+ * occur until syscalls in other threads with references complete.
+ * The filemon cannot be inherited after this though.
+ */
+ filemon_untrack_processes(filemon);
+ filemon_drop(filemon);
+}
+
+/* Attach the filemon to the process. */
+static int
+filemon_attach_proc(struct filemon *filemon, struct proc *p)
+{
+ struct filemon *filemon2;
+
+ sx_assert(&filemon->lock, SA_XLOCKED);
+ PROC_LOCK_ASSERT(p, MA_OWNED);
+ KASSERT((p->p_flag & P_WEXIT) == 0,
+ ("%s: filemon %p attaching to exiting process %p",
+ __func__, filemon, p));
+
+ if (p->p_filemon == filemon)
+ return (0);
+ /*
+ * Don't allow truncating other process traces. It is
+ * not really intended to trace procs other than curproc
+ * anyhow.
+ */
+ if (p->p_filemon != NULL && p != curproc)
+ return (EBUSY);
+ /*
+ * Historic behavior of filemon has been to let a child initiate
+ * tracing on itself and cease existing tracing. Bmake
+ * .META + .MAKE relies on this. It is only relevant for attaching to
+ * curproc.
+ */
+ while (p->p_filemon != NULL) {
+ PROC_UNLOCK(p);
+ sx_xunlock(&filemon->lock);
+ while ((filemon2 = filemon_proc_get(p)) != NULL) {
+ /* It may have changed. */
+ if (p->p_filemon == filemon2)
+ filemon_proc_drop(p);
+ filemon_drop(filemon2);
+ }
+ sx_xlock(&filemon->lock);
+ PROC_LOCK(p);
+ /*
+ * It may have been attached to, though unlikely.
+ * Try again if needed.
+ */
}
+
+ KASSERT(p->p_filemon == NULL,
+ ("%s: proc %p didn't detach filemon %p", __func__, p,
+ p->p_filemon));
+ p->p_filemon = filemon_acquire(filemon);
+ ++filemon->proccnt;
+
+ return (0);
}
static int
@@ -178,10 +365,16 @@ filemon_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag __unused,
/* Set the monitored process ID. */
case FILEMON_SET_PID:
+ /* Invalidate any existing processes already set. */
+ filemon_untrack_processes(filemon);
+
error = pget(*((pid_t *)data), PGET_CANDEBUG | PGET_NOTWEXIT,
&p);
if (error == 0) {
- filemon->p = p;
+ KASSERT(p->p_filemon != filemon,
+ ("%s: proc %p didn't untrack filemon %p",
+ __func__, p, filemon));
+ error = filemon_attach_proc(filemon, p);
PROC_UNLOCK(p);
}
break;
@@ -199,35 +392,19 @@ static int
filemon_open(struct cdev *dev, int oflags __unused, int devtype __unused,
struct thread *td __unused)
{
+ int error;
struct filemon *filemon;
- /* Get exclusive write access. */
- filemon_lock_write();
-
- if ((filemon = TAILQ_FIRST(&filemons_free)) != NULL)
- TAILQ_REMOVE(&filemons_free, filemon, link);
+ filemon = malloc(sizeof(*filemon), M_FILEMON,
+ M_WAITOK | M_ZERO);
+ sx_init(&filemon->lock, "filemon");
+ refcount_init(&filemon->refcnt, 1);
- /* Give up write access. */
- filemon_unlock_write();
+ error = devfs_set_cdevpriv(filemon, filemon_dtr);
+ if (error != 0)
+ filemon_release(filemon);
- if (filemon == NULL) {
- filemon = malloc(sizeof(struct filemon), M_FILEMON,
- M_WAITOK | M_ZERO);
- sx_init(&filemon->lock, "filemon");
- }
-
- 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);
+ return (error);
}
static int
@@ -241,7 +418,6 @@ filemon_close(struct cdev *dev __unused, int flag __unused, int fmt __unused,
static void
filemon_load(void *dummy __unused)
{
- sx_init(&access_lock, "filemons_inuse");
/* Install the syscall wrappers. */
filemon_wrapper_install();
@@ -253,38 +429,11 @@ filemon_load(void *dummy __unused)
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);
- }
+ destroy_dev(filemon_dev);
+ filemon_wrapper_deinstall();
- return (error);
+ return (0);
}
static int
diff --git a/sys/dev/filemon/filemon_lock.c b/sys/dev/filemon/filemon_lock.c
deleted file mode 100644
index 5cac47c7386e..000000000000
--- a/sys/dev/filemon/filemon_lock.c
+++ /dev/null
@@ -1,57 +0,0 @@
-/*-
- * 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 <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-static __inline void
-filemon_lock_read(void)
-{
-
- sx_slock(&access_lock);
-}
-
-static __inline void
-filemon_unlock_read(void)
-{
-
- sx_sunlock(&access_lock);
-}
-
-static __inline void
-filemon_lock_write(void)
-{
-
- sx_xlock(&access_lock);
-}
-
-static __inline void
-filemon_unlock_write(void)
-{
-
- sx_xunlock(&access_lock);
-}
diff --git a/sys/dev/filemon/filemon_wrapper.c b/sys/dev/filemon/filemon_wrapper.c
index 6911dc57837d..8b064372be7e 100644
--- a/sys/dev/filemon/filemon_wrapper.c
+++ b/sys/dev/filemon/filemon_wrapper.c
@@ -1,7 +1,7 @@
/*-
* Copyright (c) 2011, David E. O'Brien.
* Copyright (c) 2009-2011, Juniper Networks, Inc.
- * Copyright (c) 2015, EMC Corp.
+ * Copyright (c) 2015-2016, EMC Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -65,33 +65,6 @@ filemon_output(struct filemon *filemon, char *msg, size_t len)
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->p_pid != 0) {
- TAILQ_FOREACH(filemon, &filemons_inuse, link) {
- if (p == filemon->p) {
- sx_sunlock(&proctree_lock);
- sx_xlock(&filemon->lock);
- filemon_unlock_read();
- return (filemon);
- }
- }
- p = proc_realparent(p);
- }
- sx_sunlock(&proctree_lock);
- filemon_unlock_read();
- return (NULL);
-}
-
static int
filemon_wrapper_chdir(struct thread *td, struct chdir_args *uap)
{
@@ -101,7 +74,7 @@ filemon_wrapper_chdir(struct thread *td, struct chdir_args *uap)
struct filemon *filemon;
if ((ret = sys_chdir(td, uap)) == 0) {
- if ((filemon = filemon_pid_check(curproc)) != NULL) {
+ if ((filemon = filemon_proc_get(curproc)) != NULL) {
copyinstr(uap->path, filemon->fname1,
sizeof(filemon->fname1), &done);
@@ -111,7 +84,7 @@ filemon_wrapper_chdir(struct thread *td, struct chdir_args *uap)
filemon_output(filemon, filemon->msgbufr, len);
- sx_xunlock(&filemon->lock);
+ filemon_drop(filemon);
}
}
@@ -126,7 +99,7 @@ filemon_event_process_exec(void *arg __unused, struct proc *p,
char *fullpath, *freepath;
size_t len;
- if ((filemon = filemon_pid_check(p)) != NULL) {
+ if ((filemon = filemon_proc_get(p)) != NULL) {
fullpath = "<unknown>";
freepath = NULL;
@@ -139,7 +112,7 @@ filemon_event_process_exec(void *arg __unused, struct proc *p,
filemon_output(filemon, filemon->msgbufr, len);
- sx_xunlock(&filemon->lock);
+ filemon_drop(filemon);
free(freepath, M_TEMP);
}
@@ -154,7 +127,7 @@ filemon_wrapper_open(struct thread *td, struct open_args *uap)
struct filemon *filemon;
if ((ret = sys_open(td, uap)) == 0) {
- if ((filemon = filemon_pid_check(curproc)) != NULL) {
+ if ((filemon = filemon_proc_get(curproc)) != NULL) {
copyinstr(uap->path, filemon->fname1,
sizeof(filemon->fname1), &done);
@@ -177,7 +150,7 @@ filemon_wrapper_open(struct thread *td, struct open_args *uap)
curproc->p_pid, filemon->fname1);
filemon_output(filemon, filemon->msgbufr, len);
- sx_xunlock(&filemon->lock);
+ filemon_drop(filemon);
}
}
@@ -193,7 +166,7 @@ filemon_wrapper_openat(struct thread *td, struct openat_args *uap)
struct filemon *filemon;
if ((ret = sys_openat(td, uap)) == 0) {
- if ((filemon = filemon_pid_check(curproc)) != NULL) {
+ if ((filemon = filemon_proc_get(curproc)) != NULL) {
copyinstr(uap->path, filemon->fname1,
sizeof(filemon->fname1), &done);
@@ -229,7 +202,7 @@ filemon_wrapper_openat(struct thread *td, struct openat_args *uap)
curproc->p_pid, filemon->fname2, filemon->fname1);
filemon_output(filemon, filemon->msgbufr, len);
- sx_xunlock(&filemon->lock);
+ filemon_drop(filemon);
}
}
@@ -245,7 +218,7 @@ filemon_wrapper_rename(struct thread *td, struct rename_args *uap)
struct filemon *filemon;
if ((ret = sys_rename(td, uap)) == 0) {
- if ((filemon = filemon_pid_check(curproc)) != NULL) {
+ if ((filemon = filemon_proc_get(curproc)) != NULL) {
copyinstr(uap->from, filemon->fname1,
sizeof(filemon->fname1), &done);
copyinstr(uap->to, filemon->fname2,
@@ -257,7 +230,7 @@ filemon_wrapper_rename(struct thread *td, struct rename_args *uap)
filemon_output(filemon, filemon->msgbufr, len);
- sx_xunlock(&filemon->lock);
+ filemon_drop(filemon);
}
}
@@ -273,7 +246,7 @@ filemon_wrapper_link(struct thread *td, struct link_args *uap)
struct filemon *filemon;
if ((ret = sys_link(td, uap)) == 0) {
- if ((filemon = filemon_pid_check(curproc)) != NULL) {
+ if ((filemon = filemon_proc_get(curproc)) != NULL) {
copyinstr(uap->path, filemon->fname1,
sizeof(filemon->fname1), &done);
copyinstr(uap->link, filemon->fname2,
@@ -285,7 +258,7 @@ filemon_wrapper_link(struct thread *td, struct link_args *uap)
filemon_output(filemon, filemon->msgbufr, len);
- sx_xunlock(&filemon->lock);
+ filemon_drop(filemon);
}
}
@@ -301,7 +274,7 @@ filemon_wrapper_symlink(struct thread *td, struct symlink_args *uap)
struct filemon *filemon;
if ((ret = sys_symlink(td, uap)) == 0) {
- if ((filemon = filemon_pid_check(curproc)) != NULL) {
+ if ((filemon = filemon_proc_get(curproc)) != NULL) {
copyinstr(uap->path, filemon->fname1,
sizeof(filemon->fname1), &done);
copyinstr(uap->link, filemon->fname2,
@@ -313,7 +286,7 @@ filemon_wrapper_symlink(struct thread *td, struct symlink_args *uap)
filemon_output(filemon, filemon->msgbufr, len);
- sx_xunlock(&filemon->lock);
+ filemon_drop(filemon);
}
}
@@ -329,7 +302,7 @@ filemon_wrapper_linkat(struct thread *td, struct linkat_args *uap)
struct filemon *filemon;
if ((ret = sys_linkat(td, uap)) == 0) {
- if ((filemon = filemon_pid_check(curproc)) != NULL) {
+ if ((filemon = filemon_proc_get(curproc)) != NULL) {
copyinstr(uap->path1, filemon->fname1,
sizeof(filemon->fname1), &done);
copyinstr(uap->path2, filemon->fname2,
@@ -341,7 +314,7 @@ filemon_wrapper_linkat(struct thread *td, struct linkat_args *uap)
filemon_output(filemon, filemon->msgbufr, len);
- sx_xunlock(&filemon->lock);
+ filemon_drop(filemon);
}
}
@@ -357,7 +330,7 @@ filemon_wrapper_stat(struct thread *td, struct stat_args *uap)
struct filemon *filemon;
if ((ret = sys_stat(td, uap)) == 0) {
- if ((filemon = filemon_pid_check(curproc)) != NULL) {
+ if ((filemon = filemon_proc_get(curproc)) != NULL) {
copyinstr(uap->path, filemon->fname1,
sizeof(filemon->fname1), &done);
@@ -367,7 +340,7 @@ filemon_wrapper_stat(struct thread *td, struct stat_args *uap)
filemon_output(filemon, filemon->msgbufr, len);
- sx_xunlock(&filemon->lock);
+ filemon_drop(filemon);
}
}
@@ -385,7 +358,7 @@ filemon_wrapper_freebsd32_stat(struct thread *td,
struct filemon *filemon;
if ((ret = freebsd32_stat(td, uap)) == 0) {
- if ((filemon = filemon_pid_check(curproc)) != NULL) {
+ if ((filemon = filemon_proc_get(curproc)) != NULL) {
copyinstr(uap->path, filemon->fname1,
sizeof(filemon->fname1), &done);
@@ -395,7 +368,7 @@ filemon_wrapper_freebsd32_stat(struct thread *td,
filemon_output(filemon, filemon->msgbufr, len);
- sx_xunlock(&filemon->lock);
+ filemon_drop(filemon);
}
}
@@ -408,29 +381,25 @@ 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(p)) != NULL) {
+ if ((filemon = filemon_proc_get(p)) != NULL) {
len = snprintf(filemon->msgbufr, sizeof(filemon->msgbufr),
"X %d %d %d\n", p->p_pid, p->p_xexit, p->p_xsig);
filemon_output(filemon, filemon->msgbufr, len);
- /* Check if the monitored process is about to exit. */
- 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->p = NULL;
- }
-
- sx_xunlock(&filemon->lock);
+ /*
+ * filemon_untrack_processes() may have dropped this p_filemon
+ * already while in filemon_proc_get() before acquiring the
+ * filemon lock.
+ */
+ KASSERT(p->p_filemon == NULL || p->p_filemon == filemon,
+ ("%s: p %p was attached while exiting, expected "
+ "filemon %p or NULL", __func__, p, filemon));
+ if (p->p_filemon == filemon)
+ filemon_proc_drop(p);
+
+ filemon_drop(filemon);
}
}
@@ -443,7 +412,7 @@ filemon_wrapper_unlink(struct thread *td, struct unlink_args *uap)
struct filemon *filemon;
if ((ret = sys_unlink(td, uap)) == 0) {
- if ((filemon = filemon_pid_check(curproc)) != NULL) {
+ if ((filemon = filemon_proc_get(curproc)) != NULL) {
copyinstr(uap->path, filemon->fname1,
sizeof(filemon->fname1), &done);
@@ -453,7 +422,7 @@ filemon_wrapper_unlink(struct thread *td, struct unlink_args *uap)
filemon_output(filemon, filemon->msgbufr, len);
- sx_xunlock(&filemon->lock);
+ filemon_drop(filemon);
}
}
@@ -467,14 +436,34 @@ filemon_event_process_fork(void *arg __unused, struct proc *p1,
size_t len;
struct filemon *filemon;
- if ((filemon = filemon_pid_check(p1)) != NULL) {
+ if ((filemon = filemon_proc_get(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);
- sx_xunlock(&filemon->lock);
+ /*
+ * filemon_untrack_processes() or
+ * filemon_ioctl(FILEMON_SET_PID) may have changed the parent's
+ * p_filemon while in filemon_proc_get() before acquiring the
+ * filemon lock. Only inherit if the parent is still traced by
+ * this filemon.
+ */
+ if (p1->p_filemon == filemon) {
+ PROC_LOCK(p2);
+ /*
+ * It may have been attached to already by a new
+ * filemon.
+ */
+ if (p2->p_filemon == NULL) {
+ p2->p_filemon = filemon_acquire(filemon);
+ ++filemon->proccnt;
+ }
+ PROC_UNLOCK(p2);
+ }
+
+ filemon_drop(filemon);
}
}
diff --git a/sys/sys/param.h b/sys/sys/param.h
index dc3b035eaa0f..987453c418a6 100644
--- a/sys/sys/param.h
+++ b/sys/sys/param.h
@@ -58,7 +58,7 @@
* in the range 5 to 9.
*/
#undef __FreeBSD_version
-#define __FreeBSD_version 1100103 /* Master, propagated to newvers */
+#define __FreeBSD_version 1100104 /* Master, propagated to newvers */
/*
* __FreeBSD_kernel__ indicates that this system uses the kernel of FreeBSD,
diff --git a/sys/sys/proc.h b/sys/sys/proc.h
index f9ca6d9ae9a1..5d96406b8756 100644
--- a/sys/sys/proc.h
+++ b/sys/sys/proc.h
@@ -162,6 +162,7 @@ struct pargs {
*/
struct cpuset;
struct filecaps;
+struct filemon;
struct kaioinfo;
struct kaudit_record;
struct kdtrace_proc;
@@ -580,6 +581,7 @@ struct proc {
struct procdesc *p_procdesc; /* (e) Process descriptor, if any. */
u_int p_treeflag; /* (e) P_TREE flags */
int p_pendingexits; /* (c) Count of pending thread exits. */
+ struct filemon *p_filemon; /* (c) filemon-specific data. */
/* End area that is zeroed on creation. */
#define p_endzero p_magic