summaryrefslogtreecommitdiffstats
path: root/sys/dev/filemon/filemon_wrapper.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/filemon/filemon_wrapper.c')
-rw-r--r--sys/dev/filemon/filemon_wrapper.c423
1 files changed, 170 insertions, 253 deletions
diff --git a/sys/dev/filemon/filemon_wrapper.c b/sys/dev/filemon/filemon_wrapper.c
index 6911dc5..87c9392 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
@@ -29,8 +29,9 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
-#include <sys/imgact.h>
#include <sys/eventhandler.h>
+#include <sys/filedesc.h>
+#include <sys/imgact.h>
#include <sys/sx.h>
#include <sys/vnode.h>
@@ -45,6 +46,7 @@ filemon_output(struct filemon *filemon, char *msg, size_t len)
{
struct uio auio;
struct iovec aiov;
+ int error;
if (filemon->fp == NULL)
return;
@@ -62,56 +64,33 @@ filemon_output(struct filemon *filemon, char *msg, size_t len)
if (filemon->fp->f_type == DTYPE_VNODE)
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->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);
+ error = fo_write(filemon->fp, &auio, curthread->td_ucred, 0, curthread);
+ if (error != 0)
+ filemon->error = error;
}
static int
filemon_wrapper_chdir(struct thread *td, struct chdir_args *uap)
{
- int ret;
- size_t done;
+ int error, ret;
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);
+ if ((filemon = filemon_proc_get(curproc)) != NULL) {
+ if ((error = copyinstr(uap->path, filemon->fname1,
+ sizeof(filemon->fname1), NULL)) != 0) {
+ filemon->error = error;
+ goto copyfail;
+ }
len = snprintf(filemon->msgbufr,
sizeof(filemon->msgbufr), "C %d %s\n",
curproc->p_pid, filemon->fname1);
filemon_output(filemon, filemon->msgbufr, len);
-
- sx_xunlock(&filemon->lock);
+copyfail:
+ filemon_drop(filemon);
}
}
@@ -126,12 +105,11 @@ 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;
- vn_fullpath(FIRST_THREAD_IN_PROC(p), imgp->vp, &fullpath,
- &freepath);
+ vn_fullpath(curthread, imgp->vp, &fullpath, &freepath);
len = snprintf(filemon->msgbufr,
sizeof(filemon->msgbufr), "E %d %s\n",
@@ -139,321 +117,244 @@ 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);
}
}
-static int
-filemon_wrapper_open(struct thread *td, struct open_args *uap)
+static void
+_filemon_wrapper_openat(struct thread *td, char *upath, int flags, int fd)
{
- int ret;
- size_t done;
+ int error;
size_t len;
+ struct file *fp;
struct filemon *filemon;
+ char *atpath, *freepath;
+ cap_rights_t rights;
- 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);
- }
+ if ((filemon = filemon_proc_get(curproc)) != NULL) {
+ atpath = "";
+ freepath = NULL;
+ fp = NULL;
+ if ((error = copyinstr(upath, filemon->fname1,
+ sizeof(filemon->fname1), NULL)) != 0) {
+ filemon->error = error;
+ goto copyfail;
+ }
+ if (filemon->fname1[0] != '/' && 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.
+ * XXX: This may be able to come out with
+ * the namecache lookup now.
+ */
len = snprintf(filemon->msgbufr,
- sizeof(filemon->msgbufr), "%c %d %s\n",
- (uap->flags & O_ACCMODE) ? 'W':'R',
+ sizeof(filemon->msgbufr), "A %d %s\n",
curproc->p_pid, filemon->fname1);
filemon_output(filemon, filemon->msgbufr, len);
-
- sx_xunlock(&filemon->lock);
+ /*
+ * Try to resolve the path from the vnode using the
+ * namecache. It may be inaccurate, but better
+ * than nothing.
+ */
+ if (getvnode(td, fd,
+ cap_rights_init(&rights, CAP_LOOKUP), &fp) == 0) {
+ vn_fullpath(td, fp->f_vnode, &atpath,
+ &freepath);
+ }
+ }
+ if (flags & O_RDWR) {
+ /*
+ * We'll get the W record below, but need
+ * to also output an R to distinguish from
+ * O_WRONLY.
+ */
+ len = snprintf(filemon->msgbufr,
+ sizeof(filemon->msgbufr), "R %d %s%s%s\n",
+ curproc->p_pid, atpath,
+ atpath[0] != '\0' ? "/" : "", filemon->fname1);
+ filemon_output(filemon, filemon->msgbufr, len);
}
- }
- return (ret);
+ len = snprintf(filemon->msgbufr,
+ sizeof(filemon->msgbufr), "%c %d %s%s%s\n",
+ (flags & O_ACCMODE) ? 'W':'R',
+ curproc->p_pid, atpath,
+ atpath[0] != '\0' ? "/" : "", filemon->fname1);
+ filemon_output(filemon, filemon->msgbufr, len);
+copyfail:
+ filemon_drop(filemon);
+ if (fp != NULL)
+ fdrop(fp, td);
+ free(freepath, M_TEMP);
+ }
}
static int
-filemon_wrapper_openat(struct thread *td, struct openat_args *uap)
+filemon_wrapper_open(struct thread *td, struct open_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);
-
- sx_xunlock(&filemon->lock);
- }
- }
+ if ((ret = sys_open(td, uap)) == 0)
+ _filemon_wrapper_openat(td, uap->path, uap->flags, AT_FDCWD);
return (ret);
}
static int
-filemon_wrapper_rename(struct thread *td, struct rename_args *uap)
+filemon_wrapper_openat(struct thread *td, struct openat_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);
-
- sx_xunlock(&filemon->lock);
- }
- }
+ if ((ret = sys_openat(td, uap)) == 0)
+ _filemon_wrapper_openat(td, uap->path, uap->flag, uap->fd);
return (ret);
}
static int
-filemon_wrapper_link(struct thread *td, struct link_args *uap)
+filemon_wrapper_rename(struct thread *td, struct rename_args *uap)
{
- int ret;
- size_t done;
+ int error, ret;
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);
+ if ((ret = sys_rename(td, uap)) == 0) {
+ if ((filemon = filemon_proc_get(curproc)) != NULL) {
+ if (((error = copyinstr(uap->from, filemon->fname1,
+ sizeof(filemon->fname1), NULL)) != 0) ||
+ ((error = copyinstr(uap->to, filemon->fname2,
+ sizeof(filemon->fname2), NULL)) != 0)) {
+ filemon->error = error;
+ goto copyfail;
+ }
len = snprintf(filemon->msgbufr,
- sizeof(filemon->msgbufr), "L %d '%s' '%s'\n",
+ sizeof(filemon->msgbufr), "M %d '%s' '%s'\n",
curproc->p_pid, filemon->fname1, filemon->fname2);
filemon_output(filemon, filemon->msgbufr, len);
-
- sx_xunlock(&filemon->lock);
+copyfail:
+ filemon_drop(filemon);
}
}
return (ret);
}
-static int
-filemon_wrapper_symlink(struct thread *td, struct symlink_args *uap)
+static void
+_filemon_wrapper_link(struct thread *td, char *upath1, char *upath2)
{
- int ret;
- size_t done;
- size_t len;
struct filemon *filemon;
+ size_t len;
+ int error;
+
+ if ((filemon = filemon_proc_get(curproc)) != NULL) {
+ if (((error = copyinstr(upath1, filemon->fname1,
+ sizeof(filemon->fname1), NULL)) != 0) ||
+ ((error = copyinstr(upath2, filemon->fname2,
+ sizeof(filemon->fname2), NULL)) != 0)) {
+ filemon->error = error;
+ goto copyfail;
+ }
- 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);
+ len = snprintf(filemon->msgbufr,
+ sizeof(filemon->msgbufr), "L %d '%s' '%s'\n",
+ curproc->p_pid, filemon->fname1, filemon->fname2);
- sx_xunlock(&filemon->lock);
- }
+ filemon_output(filemon, filemon->msgbufr, len);
+copyfail:
+ filemon_drop(filemon);
}
-
- return (ret);
}
static int
-filemon_wrapper_linkat(struct thread *td, struct linkat_args *uap)
+filemon_wrapper_link(struct thread *td, struct link_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);
-
- sx_xunlock(&filemon->lock);
- }
- }
+ if ((ret = sys_link(td, uap)) == 0)
+ _filemon_wrapper_link(td, uap->path, uap->link);
return (ret);
}
static int
-filemon_wrapper_stat(struct thread *td, struct stat_args *uap)
+filemon_wrapper_symlink(struct thread *td, struct symlink_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);
-
- sx_xunlock(&filemon->lock);
- }
- }
+ if ((ret = sys_symlink(td, uap)) == 0)
+ _filemon_wrapper_link(td, uap->path, uap->link);
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)
+filemon_wrapper_linkat(struct thread *td, struct linkat_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);
- sx_xunlock(&filemon->lock);
- }
- }
+ if ((ret = sys_linkat(td, uap)) == 0)
+ _filemon_wrapper_link(td, uap->path1, uap->path2);
return (ret);
}
-#endif
static void
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);
}
}
static int
filemon_wrapper_unlink(struct thread *td, struct unlink_args *uap)
{
- int ret;
- size_t done;
+ int error, ret;
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);
+ if ((filemon = filemon_proc_get(curproc)) != NULL) {
+ if ((error = copyinstr(uap->path, filemon->fname1,
+ sizeof(filemon->fname1), NULL)) != 0) {
+ filemon->error = error;
+ goto copyfail;
+ }
len = snprintf(filemon->msgbufr,
sizeof(filemon->msgbufr), "D %d %s\n",
curproc->p_pid, filemon->fname1);
filemon_output(filemon, filemon->msgbufr, len);
-
- sx_xunlock(&filemon->lock);
+copyfail:
+ filemon_drop(filemon);
}
}
@@ -467,14 +368,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);
}
}
@@ -491,7 +412,6 @@ filemon_wrapper_install(void)
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_link].sy_call = (sy_call_t *) filemon_wrapper_link;
sv_table[SYS_symlink].sy_call = (sy_call_t *) filemon_wrapper_symlink;
@@ -504,7 +424,6 @@ filemon_wrapper_install(void)
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_link].sy_call = (sy_call_t *) filemon_wrapper_link;
sv_table[FREEBSD32_SYS_symlink].sy_call = (sy_call_t *) filemon_wrapper_symlink;
@@ -532,7 +451,6 @@ filemon_wrapper_deinstall(void)
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_link].sy_call = (sy_call_t *)sys_link;
sv_table[SYS_symlink].sy_call = (sy_call_t *)sys_symlink;
@@ -545,7 +463,6 @@ filemon_wrapper_deinstall(void)
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_link].sy_call = (sy_call_t *)sys_link;
sv_table[FREEBSD32_SYS_symlink].sy_call = (sy_call_t *)sys_symlink;
OpenPOWER on IntegriCloud