Page MenuHomeFreeBSD

D5520.id14139.diff
No OneTemporary

D5520.id14139.diff

Index: share/man/man4/filemon.4
===================================================================
--- share/man/man4/filemon.4
+++ share/man/man4/filemon.4
@@ -31,7 +31,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd January 28, 2016
+.Dd March 2, 2016
.Dt FILEMON 4
.Os
.Sh NAME
@@ -186,11 +186,4 @@
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.
+Unloading the module may panic the system.
Index: sys/dev/filemon/filemon.c
===================================================================
--- sys/dev/filemon/filemon.c
+++ sys/dev/filemon/filemon.c
@@ -46,7 +46,6 @@
#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>
@@ -68,8 +67,6 @@
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,
@@ -83,22 +80,83 @@
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. */
- 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. */
+ volatile u_int refcnt; /* Pointer reference 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;
-#include "filemon_lock.c"
+static __inline struct filemon *
+filemon_acquire(struct filemon *filemon)
+{
+
+ if (filemon != NULL)
+ refcount_acquire(&filemon->refcnt);
+ return (filemon);
+}
+
+static __inline void
+filemon_release(struct filemon *filemon)
+{
+
+ refcount_release(&filemon->refcnt);
+}
+
+static void
+filemon_drain(struct filemon *filemon)
+{
+
+ while (filemon->refcnt > 0)
+ pause("filemon", hz / 10);
+}
+
+static struct filemon *
+filemon_proc_get(struct proc *p)
+{
+ struct filemon *filemon;
+
+ filemon = filemon_acquire(p->p_filemon);
+
+ if (filemon == NULL)
+ return (NULL);
+ sx_xlock(&filemon->lock);
+ return (filemon);
+}
+
+static void
+filemon_proc_put(struct proc *p, struct filemon *filemon)
+{
+
+ KASSERT(p->p_filemon == NULL, ("%s: proc %p non-NULL filemon %p",
+ __func__, p, p->p_filemon));
+ sx_assert(&filemon->lock, SA_XLOCKED);
+ p->p_filemon = filemon_acquire(filemon);
+}
+
+static void
+filemon_proc_drop(struct proc *p)
+{
+ struct filemon *filemon;
+
+ filemon = p->p_filemon;
+ KASSERT(filemon != NULL, ("%s: proc %p NULL filemon", __func__, p));
+ sx_assert(&filemon->lock, SA_XLOCKED);
+ filemon_release(filemon);
+ p->p_filemon = NULL;
+}
+
+static __inline void
+filemon_drop(struct filemon *filemon)
+{
+
+ sx_xunlock(&filemon->lock);
+ filemon_release(filemon);
+}
+
#include "filemon_wrapper.c"
static void
@@ -118,34 +176,69 @@
}
static void
-filemon_dtr(void *data)
+filemon_free(struct filemon *filemon)
{
- struct filemon *filemon = data;
-
- if (filemon != NULL) {
- struct file *fp;
+ size_t len;
+ struct timeval now;
- /* Follow same locking order as filemon_pid_check. */
- filemon_lock_write();
- sx_xlock(&filemon->lock);
+ if (filemon->fp != NULL) {
+ getmicrotime(&now);
- /* Remove from the in-use list. */
- TAILQ_REMOVE(&filemons_inuse, filemon, link);
+ len = snprintf(filemon->msgbufr,
+ sizeof(filemon->msgbufr),
+ "# Stop %ju.%06ju\n# Bye bye\n",
+ (uintmax_t)now.tv_sec, (uintmax_t)now.tv_usec);
- fp = filemon->fp;
- filemon->fp = NULL;
- filemon->p = NULL;
+ filemon_output(filemon, filemon->msgbufr, len);
+ fdrop(filemon->fp, curthread);
+ }
- /* Add to the free list. */
- TAILQ_INSERT_TAIL(&filemons_free, filemon, link);
+ sx_destroy(&filemon->lock);
+ free(filemon, M_FILEMON);
+}
- /* Give up write access. */
- sx_xunlock(&filemon->lock);
- filemon_unlock_write();
+/*
+ * Invalidate the passed filemon in all processes.
+ */
+static void
+filemon_untrack_processes(struct filemon *filemon)
+{
+ struct proc *p;
- if (fp != NULL)
- fdrop(fp, curthread);
+ sx_assert(&filemon->lock, SA_XLOCKED);
+
+ /* First reference is in the cdevpriv. */
+ if (filemon->refcnt == 1)
+ return;
+
+ /*
+ * 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) {
+ /* Protected by filemon lock. */
+ if (p->p_filemon == filemon)
+ filemon_proc_drop(p);
}
+ sx_sunlock(&allproc_lock);
+}
+
+/* The devfs file is being closed. Untrace all processes and cleanup. */
+static void
+filemon_dtr(void *data)
+{
+ struct filemon *filemon = data;
+
+ if (filemon == NULL)
+ return;
+
+ sx_xlock(&filemon->lock);
+ filemon_untrack_processes(filemon);
+ filemon_drop(filemon);
+ filemon_drain(filemon);
+ filemon_free(filemon);
}
static int
@@ -178,10 +271,16 @@
/* 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;
+ if (p->p_filemon != NULL)
+ error = EBUSY;
+ else
+ filemon_proc_put(p, filemon);
PROC_UNLOCK(p);
}
break;
@@ -199,35 +298,21 @@
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(struct filemon), M_FILEMON,
+ M_WAITOK | M_ZERO);
+ sx_init(&filemon->lock, "filemon");
+ refcount_init(&filemon->refcnt, 1);
- /* 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");
+ error = devfs_set_cdevpriv(filemon, filemon_dtr);
+ if (error != 0) {
+ refcount_release(&filemon->refcnt);
+ filemon_free(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 +326,6 @@
static void
filemon_load(void *dummy __unused)
{
- sx_init(&access_lock, "filemons_inuse");
/* Install the syscall wrappers. */
filemon_wrapper_install();
@@ -253,38 +337,11 @@
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();
- }
+ destroy_dev(filemon_dev);
+ 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);
+ return (0);
}
static int
@@ -301,6 +358,13 @@
error = filemon_unload();
break;
+ case MOD_QUIESCE:
+ /*
+ * The wrapper implementation is unsafe for reliable unload.
+ * Require forcing an unload.
+ */
+ error = EBUSY;
+
case MOD_SHUTDOWN:
break;
Index: sys/dev/filemon/filemon_lock.c
===================================================================
--- 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);
-}
Index: sys/dev/filemon/filemon_wrapper.c
===================================================================
--- sys/dev/filemon/filemon_wrapper.c
+++ sys/dev/filemon/filemon_wrapper.c
@@ -64,33 +64,6 @@
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)
{
@@ -100,7 +73,7 @@
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);
@@ -110,7 +83,7 @@
filemon_output(filemon, filemon->msgbufr, len);
- sx_xunlock(&filemon->lock);
+ filemon_drop(filemon);
}
}
@@ -125,7 +98,7 @@
char *fullpath, *freepath;
size_t len;
- if ((filemon = filemon_pid_check(p)) != NULL) {
+ if ((filemon = filemon_proc_get(p)) != NULL) {
fullpath = "<unknown>";
freepath = NULL;
@@ -138,7 +111,7 @@
filemon_output(filemon, filemon->msgbufr, len);
- sx_xunlock(&filemon->lock);
+ filemon_drop(filemon);
free(freepath, M_TEMP);
}
@@ -153,7 +126,7 @@
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);
@@ -176,7 +149,7 @@
curproc->p_pid, filemon->fname1);
filemon_output(filemon, filemon->msgbufr, len);
- sx_xunlock(&filemon->lock);
+ filemon_drop(filemon);
}
}
@@ -192,7 +165,7 @@
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);
@@ -228,7 +201,7 @@
curproc->p_pid, filemon->fname2, filemon->fname1);
filemon_output(filemon, filemon->msgbufr, len);
- sx_xunlock(&filemon->lock);
+ filemon_drop(filemon);
}
}
@@ -244,7 +217,7 @@
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,
@@ -256,7 +229,7 @@
filemon_output(filemon, filemon->msgbufr, len);
- sx_xunlock(&filemon->lock);
+ filemon_drop(filemon);
}
}
@@ -272,7 +245,7 @@
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,
@@ -284,7 +257,7 @@
filemon_output(filemon, filemon->msgbufr, len);
- sx_xunlock(&filemon->lock);
+ filemon_drop(filemon);
}
}
@@ -300,7 +273,7 @@
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,
@@ -312,7 +285,7 @@
filemon_output(filemon, filemon->msgbufr, len);
- sx_xunlock(&filemon->lock);
+ filemon_drop(filemon);
}
}
@@ -328,7 +301,7 @@
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,
@@ -340,7 +313,7 @@
filemon_output(filemon, filemon->msgbufr, len);
- sx_xunlock(&filemon->lock);
+ filemon_drop(filemon);
}
}
@@ -356,7 +329,7 @@
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);
@@ -366,7 +339,7 @@
filemon_output(filemon, filemon->msgbufr, len);
- sx_xunlock(&filemon->lock);
+ filemon_drop(filemon);
}
}
@@ -384,7 +357,7 @@
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);
@@ -394,7 +367,7 @@
filemon_output(filemon, filemon->msgbufr, len);
- sx_xunlock(&filemon->lock);
+ filemon_drop(filemon);
}
}
@@ -407,29 +380,16 @@
{
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_proc_drop(p);
- filemon_output(filemon, filemon->msgbufr, len);
- filemon->p = NULL;
- }
-
- sx_xunlock(&filemon->lock);
+ filemon_drop(filemon);
}
}
@@ -442,7 +402,7 @@
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);
@@ -452,7 +412,7 @@
filemon_output(filemon, filemon->msgbufr, len);
- sx_xunlock(&filemon->lock);
+ filemon_drop(filemon);
}
}
@@ -466,14 +426,16 @@
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_proc_put(p2, filemon);
+
+ filemon_drop(filemon);
}
}
Index: sys/sys/proc.h
===================================================================
--- sys/sys/proc.h
+++ sys/sys/proc.h
@@ -162,6 +162,7 @@
*/
struct cpuset;
struct filecaps;
+struct filemon;
struct kaioinfo;
struct kaudit_record;
struct kdtrace_proc;
@@ -580,6 +581,7 @@
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; /* (*) filemon(4)-specific data. */
/* End area that is zeroed on creation. */
#define p_endzero p_magic

File Metadata

Mime Type
text/plain
Expires
Mon, Jun 15, 2:16 PM (7 h, 31 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
33970315
Default Alt Text
D5520.id14139.diff (17 KB)

Event Timeline