xref: /freebsd-src/sys/dev/filemon/filemon_wrapper.c (revision 685dc743dc3b5645e34836464128e1c0558b404b)
1eb9aea5aSDavid E. O'Brien /*-
2*4d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
3718cf2ccSPedro F. Giffuni  *
4eb9aea5aSDavid E. O'Brien  * Copyright (c) 2011, David E. O'Brien.
5eb9aea5aSDavid E. O'Brien  * Copyright (c) 2009-2011, Juniper Networks, Inc.
6e0d84b9eSBryan Drewery  * Copyright (c) 2015-2016, EMC Corp.
7eb9aea5aSDavid E. O'Brien  * All rights reserved.
8eb9aea5aSDavid E. O'Brien  *
9eb9aea5aSDavid E. O'Brien  * Redistribution and use in source and binary forms, with or without
10eb9aea5aSDavid E. O'Brien  * modification, are permitted provided that the following conditions
11eb9aea5aSDavid E. O'Brien  * are met:
12eb9aea5aSDavid E. O'Brien  * 1. Redistributions of source code must retain the above copyright
13eb9aea5aSDavid E. O'Brien  *    notice, this list of conditions and the following disclaimer.
14eb9aea5aSDavid E. O'Brien  * 2. Redistributions in binary form must reproduce the above copyright
15eb9aea5aSDavid E. O'Brien  *    notice, this list of conditions and the following disclaimer in the
16eb9aea5aSDavid E. O'Brien  *    documentation and/or other materials provided with the distribution.
17eb9aea5aSDavid E. O'Brien  *
18eb9aea5aSDavid E. O'Brien  * THIS SOFTWARE IS PROVIDED BY JUNIPER NETWORKS AND CONTRIBUTORS ``AS IS'' AND
19eb9aea5aSDavid E. O'Brien  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20eb9aea5aSDavid E. O'Brien  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21eb9aea5aSDavid E. O'Brien  * ARE DISCLAIMED. IN NO EVENT SHALL JUNIPER NETWORKS OR CONTRIBUTORS BE LIABLE
22eb9aea5aSDavid E. O'Brien  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23eb9aea5aSDavid E. O'Brien  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24eb9aea5aSDavid E. O'Brien  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25eb9aea5aSDavid E. O'Brien  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26eb9aea5aSDavid E. O'Brien  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27eb9aea5aSDavid E. O'Brien  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28eb9aea5aSDavid E. O'Brien  * SUCH DAMAGE.
29eb9aea5aSDavid E. O'Brien  */
30eb9aea5aSDavid E. O'Brien 
31eb9aea5aSDavid E. O'Brien #include <sys/cdefs.h>
3279d69913SBryan Drewery #include <sys/eventhandler.h>
338536d1b7SBryan Drewery #include <sys/filedesc.h>
348536d1b7SBryan Drewery #include <sys/imgact.h>
35f14fbe72SBryan Drewery #include <sys/priv.h>
36c849fda8SSimon J. Gerraty #include <sys/sx.h>
3766afa415SBryan Drewery #include <sys/sysent.h>
38f889a61aSBryan Drewery #include <sys/vnode.h>
39c849fda8SSimon J. Gerraty 
40bc0d7285SBryan Drewery #include <machine/stdarg.h>
41bc0d7285SBryan Drewery 
42bc0d7285SBryan Drewery static void filemon_output_event(struct filemon *filemon, const char *fmt, ...)
43bc0d7285SBryan Drewery     __printflike(2, 3);
44bc0d7285SBryan Drewery 
45f889a61aSBryan Drewery static eventhandler_tag filemon_exec_tag;
4679d69913SBryan Drewery static eventhandler_tag filemon_exit_tag;
472f600962SBryan Drewery static eventhandler_tag filemon_fork_tag;
4879d69913SBryan Drewery 
49eb9aea5aSDavid E. O'Brien static void
filemon_output(struct filemon * filemon,char * msg,size_t len)50eb9aea5aSDavid E. O'Brien filemon_output(struct filemon *filemon, char *msg, size_t len)
51eb9aea5aSDavid E. O'Brien {
52eb9aea5aSDavid E. O'Brien 	struct uio auio;
53eb9aea5aSDavid E. O'Brien 	struct iovec aiov;
544177d9f7SBryan Drewery 	int error;
55eb9aea5aSDavid E. O'Brien 
56eb9aea5aSDavid E. O'Brien 	if (filemon->fp == NULL)
57eb9aea5aSDavid E. O'Brien 		return;
58eb9aea5aSDavid E. O'Brien 
59eb9aea5aSDavid E. O'Brien 	aiov.iov_base = msg;
60eb9aea5aSDavid E. O'Brien 	aiov.iov_len = len;
61eb9aea5aSDavid E. O'Brien 	auio.uio_iov = &aiov;
62eb9aea5aSDavid E. O'Brien 	auio.uio_iovcnt = 1;
63eb9aea5aSDavid E. O'Brien 	auio.uio_resid = len;
64eb9aea5aSDavid E. O'Brien 	auio.uio_segflg = UIO_SYSSPACE;
65eb9aea5aSDavid E. O'Brien 	auio.uio_rw = UIO_WRITE;
66eb9aea5aSDavid E. O'Brien 	auio.uio_td = curthread;
67eb9aea5aSDavid E. O'Brien 	auio.uio_offset = (off_t) -1;
68eb9aea5aSDavid E. O'Brien 
698a81693aSBryan Drewery 	if (filemon->fp->f_type == DTYPE_VNODE)
70eb9aea5aSDavid E. O'Brien 		bwillwrite();
71eb9aea5aSDavid E. O'Brien 
727ae27ff9SBryan Drewery 	error = fo_write(filemon->fp, &auio, filemon->cred, 0, curthread);
73b7622235SBryan Drewery 	if (error != 0 && filemon->error == 0)
744177d9f7SBryan Drewery 		filemon->error = error;
75eb9aea5aSDavid E. O'Brien }
76eb9aea5aSDavid E. O'Brien 
77bc0d7285SBryan Drewery static void
filemon_output_event(struct filemon * filemon,const char * fmt,...)78bc0d7285SBryan Drewery filemon_output_event(struct filemon *filemon, const char *fmt, ...)
79bc0d7285SBryan Drewery {
80bc0d7285SBryan Drewery 	va_list ap;
81bc0d7285SBryan Drewery 	size_t len;
82bc0d7285SBryan Drewery 
83bc0d7285SBryan Drewery 	va_start(ap, fmt);
84bc0d7285SBryan Drewery 	len = vsnprintf(filemon->msgbufr, sizeof(filemon->msgbufr), fmt, ap);
85bc0d7285SBryan Drewery 	va_end(ap);
86bc0d7285SBryan Drewery 	/* The event is truncated but still worth logging. */
87bc0d7285SBryan Drewery 	if (len >= sizeof(filemon->msgbufr))
88bc0d7285SBryan Drewery 		len = sizeof(filemon->msgbufr) - 1;
89bc0d7285SBryan Drewery 	filemon_output(filemon, filemon->msgbufr, len);
90bc0d7285SBryan Drewery }
91bc0d7285SBryan Drewery 
92eb9aea5aSDavid E. O'Brien static int
filemon_wrapper_chdir(struct thread * td,struct chdir_args * uap)93eb9aea5aSDavid E. O'Brien filemon_wrapper_chdir(struct thread *td, struct chdir_args *uap)
94eb9aea5aSDavid E. O'Brien {
959b511ce9SBryan Drewery 	int error, ret;
96eb9aea5aSDavid E. O'Brien 	struct filemon *filemon;
97eb9aea5aSDavid E. O'Brien 
98eb9aea5aSDavid E. O'Brien 	if ((ret = sys_chdir(td, uap)) == 0) {
99e0d84b9eSBryan Drewery 		if ((filemon = filemon_proc_get(curproc)) != NULL) {
1009b511ce9SBryan Drewery 			if ((error = copyinstr(uap->path, filemon->fname1,
1019b511ce9SBryan Drewery 			    sizeof(filemon->fname1), NULL)) != 0) {
1029b511ce9SBryan Drewery 				filemon->error = error;
1039b511ce9SBryan Drewery 				goto copyfail;
1049b511ce9SBryan Drewery 			}
105eb9aea5aSDavid E. O'Brien 
106bc0d7285SBryan Drewery 			filemon_output_event(filemon, "C %d %s\n",
107eb9aea5aSDavid E. O'Brien 			    curproc->p_pid, filemon->fname1);
1089b511ce9SBryan Drewery copyfail:
109e0d84b9eSBryan Drewery 			filemon_drop(filemon);
110eb9aea5aSDavid E. O'Brien 		}
111eb9aea5aSDavid E. O'Brien 	}
112eb9aea5aSDavid E. O'Brien 
113eb9aea5aSDavid E. O'Brien 	return (ret);
114eb9aea5aSDavid E. O'Brien }
115eb9aea5aSDavid E. O'Brien 
116f889a61aSBryan Drewery static void
filemon_event_process_exec(void * arg __unused,struct proc * p,struct image_params * imgp)117f889a61aSBryan Drewery filemon_event_process_exec(void *arg __unused, struct proc *p,
118f889a61aSBryan Drewery     struct image_params *imgp)
119eb9aea5aSDavid E. O'Brien {
120eb9aea5aSDavid E. O'Brien 	struct filemon *filemon;
121eb9aea5aSDavid E. O'Brien 
122e0d84b9eSBryan Drewery 	if ((filemon = filemon_proc_get(p)) != NULL) {
123bc0d7285SBryan Drewery 		filemon_output_event(filemon, "E %d %s\n",
12423ae5cd7SBryan Drewery 		    p->p_pid,
12523ae5cd7SBryan Drewery 		    imgp->execpath != NULL ? imgp->execpath : "<unknown>");
126eb9aea5aSDavid E. O'Brien 
127f14fbe72SBryan Drewery 		/* If the credentials changed then cease tracing. */
128f14fbe72SBryan Drewery 		if (imgp->newcred != NULL &&
129f14fbe72SBryan Drewery 		    imgp->credential_setid &&
130cc426dd3SMateusz Guzik 		    priv_check_cred(filemon->cred, PRIV_DEBUG_DIFFCRED) != 0) {
131f14fbe72SBryan Drewery 			/*
132f14fbe72SBryan Drewery 			 * It may have changed to NULL already, but
133f14fbe72SBryan Drewery 			 * will not be re-attached by anything else.
134f14fbe72SBryan Drewery 			 */
135f14fbe72SBryan Drewery 			if (p->p_filemon != NULL) {
136f14fbe72SBryan Drewery 				KASSERT(p->p_filemon == filemon,
137f14fbe72SBryan Drewery 				    ("%s: proc %p didn't have expected"
138f14fbe72SBryan Drewery 				    " filemon %p", __func__, p, filemon));
139f14fbe72SBryan Drewery 				filemon_proc_drop(p);
140f14fbe72SBryan Drewery 			}
141f14fbe72SBryan Drewery 		}
142f14fbe72SBryan Drewery 
143f14fbe72SBryan Drewery 
144e0d84b9eSBryan Drewery 		filemon_drop(filemon);
145eb9aea5aSDavid E. O'Brien 	}
146eb9aea5aSDavid E. O'Brien }
147eb9aea5aSDavid E. O'Brien 
1484d3cfa1dSBryan Drewery static void
_filemon_wrapper_openat(struct thread * td,const char * upath,int flags,int fd)14912e69f96SBrooks Davis _filemon_wrapper_openat(struct thread *td, const char *upath, int flags,
15012e69f96SBrooks Davis     int fd)
151eb9aea5aSDavid E. O'Brien {
1529b511ce9SBryan Drewery 	int error;
1538536d1b7SBryan Drewery 	struct file *fp;
154eb9aea5aSDavid E. O'Brien 	struct filemon *filemon;
1558536d1b7SBryan Drewery 	char *atpath, *freepath;
1568536d1b7SBryan Drewery 	cap_rights_t rights;
157eb9aea5aSDavid E. O'Brien 
158e0d84b9eSBryan Drewery 	if ((filemon = filemon_proc_get(curproc)) != NULL) {
1598536d1b7SBryan Drewery 		atpath = "";
1608536d1b7SBryan Drewery 		freepath = NULL;
1618536d1b7SBryan Drewery 		fp = NULL;
1628536d1b7SBryan Drewery 
1639b511ce9SBryan Drewery 		if ((error = copyinstr(upath, filemon->fname1,
1649b511ce9SBryan Drewery 		    sizeof(filemon->fname1), NULL)) != 0) {
1659b511ce9SBryan Drewery 			filemon->error = error;
1669b511ce9SBryan Drewery 			goto copyfail;
1679b511ce9SBryan Drewery 		}
168f859e956SSimon J. Gerraty 
1694d3cfa1dSBryan Drewery 		if (filemon->fname1[0] != '/' && fd != AT_FDCWD) {
170f859e956SSimon J. Gerraty 			/*
171f859e956SSimon J. Gerraty 			 * rats - we cannot do too much about this.
172f859e956SSimon J. Gerraty 			 * the trace should show a dir we read
173f859e956SSimon J. Gerraty 			 * recently.. output an A record as a clue
174f859e956SSimon J. Gerraty 			 * until we can do better.
1758536d1b7SBryan Drewery 			 * XXX: This may be able to come out with
1768536d1b7SBryan Drewery 			 * the namecache lookup now.
177f859e956SSimon J. Gerraty 			 */
178bc0d7285SBryan Drewery 			filemon_output_event(filemon, "A %d %s\n",
179f859e956SSimon J. Gerraty 			    curproc->p_pid, filemon->fname1);
1808536d1b7SBryan Drewery 			/*
1818536d1b7SBryan Drewery 			 * Try to resolve the path from the vnode using the
1828536d1b7SBryan Drewery 			 * namecache.  It may be inaccurate, but better
1838536d1b7SBryan Drewery 			 * than nothing.
1848536d1b7SBryan Drewery 			 */
1858536d1b7SBryan Drewery 			if (getvnode(td, fd,
1866b3a9a0fSMateusz Guzik 			    cap_rights_init_one(&rights, CAP_LOOKUP), &fp) == 0) {
187feabaaf9SMateusz Guzik 				vn_fullpath(fp->f_vnode, &atpath, &freepath);
1888536d1b7SBryan Drewery 			}
189f859e956SSimon J. Gerraty 		}
1904d3cfa1dSBryan Drewery 		if (flags & O_RDWR) {
191f859e956SSimon J. Gerraty 			/*
192f859e956SSimon J. Gerraty 			 * We'll get the W record below, but need
1934d3cfa1dSBryan Drewery 			 * to also output an R to distinguish from
194f859e956SSimon J. Gerraty 			 * O_WRONLY.
195f859e956SSimon J. Gerraty 			 */
196bc0d7285SBryan Drewery 			filemon_output_event(filemon, "R %d %s%s%s\n",
1978536d1b7SBryan Drewery 			    curproc->p_pid, atpath,
1988536d1b7SBryan Drewery 			    atpath[0] != '\0' ? "/" : "", filemon->fname1);
199f859e956SSimon J. Gerraty 		}
200f859e956SSimon J. Gerraty 
201bc0d7285SBryan Drewery 		filemon_output_event(filemon, "%c %d %s%s%s\n",
2024d3cfa1dSBryan Drewery 		    (flags & O_ACCMODE) ? 'W':'R',
2038536d1b7SBryan Drewery 		    curproc->p_pid, atpath,
2048536d1b7SBryan Drewery 		    atpath[0] != '\0' ? "/" : "", filemon->fname1);
2059b511ce9SBryan Drewery copyfail:
206e0d84b9eSBryan Drewery 		filemon_drop(filemon);
2078536d1b7SBryan Drewery 		if (fp != NULL)
2088536d1b7SBryan Drewery 			fdrop(fp, td);
2098536d1b7SBryan Drewery 		free(freepath, M_TEMP);
210f859e956SSimon J. Gerraty 	}
211f859e956SSimon J. Gerraty }
212f859e956SSimon J. Gerraty 
2134d3cfa1dSBryan Drewery static int
filemon_wrapper_open(struct thread * td,struct open_args * uap)2144d3cfa1dSBryan Drewery filemon_wrapper_open(struct thread *td, struct open_args *uap)
2154d3cfa1dSBryan Drewery {
2164d3cfa1dSBryan Drewery 	int ret;
2174d3cfa1dSBryan Drewery 
2184d3cfa1dSBryan Drewery 	if ((ret = sys_open(td, uap)) == 0)
2194d3cfa1dSBryan Drewery 		_filemon_wrapper_openat(td, uap->path, uap->flags, AT_FDCWD);
2204d3cfa1dSBryan Drewery 
2214d3cfa1dSBryan Drewery 	return (ret);
2224d3cfa1dSBryan Drewery }
2234d3cfa1dSBryan Drewery 
2244d3cfa1dSBryan Drewery static int
filemon_wrapper_openat(struct thread * td,struct openat_args * uap)2254d3cfa1dSBryan Drewery filemon_wrapper_openat(struct thread *td, struct openat_args *uap)
2264d3cfa1dSBryan Drewery {
2274d3cfa1dSBryan Drewery 	int ret;
2284d3cfa1dSBryan Drewery 
2294d3cfa1dSBryan Drewery 	if ((ret = sys_openat(td, uap)) == 0)
2304d3cfa1dSBryan Drewery 		_filemon_wrapper_openat(td, uap->path, uap->flag, uap->fd);
2314d3cfa1dSBryan Drewery 
232f859e956SSimon J. Gerraty 	return (ret);
233f859e956SSimon J. Gerraty }
234f859e956SSimon J. Gerraty 
235f859e956SSimon J. Gerraty static int
filemon_wrapper_rename(struct thread * td,struct rename_args * uap)236eb9aea5aSDavid E. O'Brien filemon_wrapper_rename(struct thread *td, struct rename_args *uap)
237eb9aea5aSDavid E. O'Brien {
2389b511ce9SBryan Drewery 	int error, ret;
239eb9aea5aSDavid E. O'Brien 	struct filemon *filemon;
240eb9aea5aSDavid E. O'Brien 
241eb9aea5aSDavid E. O'Brien 	if ((ret = sys_rename(td, uap)) == 0) {
242e0d84b9eSBryan Drewery 		if ((filemon = filemon_proc_get(curproc)) != NULL) {
2439b511ce9SBryan Drewery 			if (((error = copyinstr(uap->from, filemon->fname1,
2449b511ce9SBryan Drewery 			     sizeof(filemon->fname1), NULL)) != 0) ||
2459b511ce9SBryan Drewery 			    ((error = copyinstr(uap->to, filemon->fname2,
2469b511ce9SBryan Drewery 			     sizeof(filemon->fname2), NULL)) != 0)) {
2479b511ce9SBryan Drewery 				filemon->error = error;
2489b511ce9SBryan Drewery 				goto copyfail;
2499b511ce9SBryan Drewery 			}
250eb9aea5aSDavid E. O'Brien 
251bc0d7285SBryan Drewery 			filemon_output_event(filemon, "M %d '%s' '%s'\n",
252eb9aea5aSDavid E. O'Brien 			    curproc->p_pid, filemon->fname1, filemon->fname2);
2539b511ce9SBryan Drewery copyfail:
254e0d84b9eSBryan Drewery 			filemon_drop(filemon);
255eb9aea5aSDavid E. O'Brien 		}
256eb9aea5aSDavid E. O'Brien 	}
257eb9aea5aSDavid E. O'Brien 
258eb9aea5aSDavid E. O'Brien 	return (ret);
259eb9aea5aSDavid E. O'Brien }
260eb9aea5aSDavid E. O'Brien 
261d77f7e8cSBryan Drewery static void
_filemon_wrapper_link(struct thread * td,const char * upath1,const char * upath2)26212e69f96SBrooks Davis _filemon_wrapper_link(struct thread *td, const char *upath1,
26312e69f96SBrooks Davis     const char *upath2)
264eb9aea5aSDavid E. O'Brien {
265eb9aea5aSDavid E. O'Brien 	struct filemon *filemon;
2669b511ce9SBryan Drewery 	int error;
267eb9aea5aSDavid E. O'Brien 
268e0d84b9eSBryan Drewery 	if ((filemon = filemon_proc_get(curproc)) != NULL) {
2699b511ce9SBryan Drewery 		if (((error = copyinstr(upath1, filemon->fname1,
2709b511ce9SBryan Drewery 		     sizeof(filemon->fname1), NULL)) != 0) ||
2719b511ce9SBryan Drewery 		    ((error = copyinstr(upath2, filemon->fname2,
2729b511ce9SBryan Drewery 		     sizeof(filemon->fname2), NULL)) != 0)) {
2739b511ce9SBryan Drewery 			filemon->error = error;
2749b511ce9SBryan Drewery 			goto copyfail;
2759b511ce9SBryan Drewery 		}
276eb9aea5aSDavid E. O'Brien 
277bc0d7285SBryan Drewery 		filemon_output_event(filemon, "L %d '%s' '%s'\n",
278eb9aea5aSDavid E. O'Brien 		    curproc->p_pid, filemon->fname1, filemon->fname2);
2799b511ce9SBryan Drewery copyfail:
280e0d84b9eSBryan Drewery 		filemon_drop(filemon);
281eb9aea5aSDavid E. O'Brien 	}
282eb9aea5aSDavid E. O'Brien }
283eb9aea5aSDavid E. O'Brien 
284d77f7e8cSBryan Drewery static int
filemon_wrapper_link(struct thread * td,struct link_args * uap)285d77f7e8cSBryan Drewery filemon_wrapper_link(struct thread *td, struct link_args *uap)
286d77f7e8cSBryan Drewery {
287d77f7e8cSBryan Drewery 	int ret;
288d77f7e8cSBryan Drewery 
289d77f7e8cSBryan Drewery 	if ((ret = sys_link(td, uap)) == 0)
290d77f7e8cSBryan Drewery 		_filemon_wrapper_link(td, uap->path, uap->link);
291d77f7e8cSBryan Drewery 
292eb9aea5aSDavid E. O'Brien 	return (ret);
293eb9aea5aSDavid E. O'Brien }
294eb9aea5aSDavid E. O'Brien 
295eb9aea5aSDavid E. O'Brien static int
filemon_wrapper_symlink(struct thread * td,struct symlink_args * uap)296eb9aea5aSDavid E. O'Brien filemon_wrapper_symlink(struct thread *td, struct symlink_args *uap)
297eb9aea5aSDavid E. O'Brien {
298eb9aea5aSDavid E. O'Brien 	int ret;
299eb9aea5aSDavid E. O'Brien 
300d77f7e8cSBryan Drewery 	if ((ret = sys_symlink(td, uap)) == 0)
301d77f7e8cSBryan Drewery 		_filemon_wrapper_link(td, uap->path, uap->link);
302eb9aea5aSDavid E. O'Brien 
303eb9aea5aSDavid E. O'Brien 	return (ret);
304eb9aea5aSDavid E. O'Brien }
305eb9aea5aSDavid E. O'Brien 
306eb9aea5aSDavid E. O'Brien static int
filemon_wrapper_linkat(struct thread * td,struct linkat_args * uap)307eb9aea5aSDavid E. O'Brien filemon_wrapper_linkat(struct thread *td, struct linkat_args *uap)
308eb9aea5aSDavid E. O'Brien {
309eb9aea5aSDavid E. O'Brien 	int ret;
310eb9aea5aSDavid E. O'Brien 
311d77f7e8cSBryan Drewery 	if ((ret = sys_linkat(td, uap)) == 0)
312d77f7e8cSBryan Drewery 		_filemon_wrapper_link(td, uap->path1, uap->path2);
313eb9aea5aSDavid E. O'Brien 
314eb9aea5aSDavid E. O'Brien 	return (ret);
315eb9aea5aSDavid E. O'Brien }
316eb9aea5aSDavid E. O'Brien 
317eb9aea5aSDavid E. O'Brien static void
filemon_event_process_exit(void * arg __unused,struct proc * p)31879d69913SBryan Drewery filemon_event_process_exit(void *arg __unused, struct proc *p)
319eb9aea5aSDavid E. O'Brien {
320eb9aea5aSDavid E. O'Brien 	struct filemon *filemon;
321eb9aea5aSDavid E. O'Brien 
322e0d84b9eSBryan Drewery 	if ((filemon = filemon_proc_get(p)) != NULL) {
323bc0d7285SBryan Drewery 		filemon_output_event(filemon, "X %d %d %d\n",
324bc0d7285SBryan Drewery 		    p->p_pid, p->p_xexit, p->p_xsig);
325eb9aea5aSDavid E. O'Brien 
326e0d84b9eSBryan Drewery 		/*
327e0d84b9eSBryan Drewery 		 * filemon_untrack_processes() may have dropped this p_filemon
328e0d84b9eSBryan Drewery 		 * already while in filemon_proc_get() before acquiring the
329e0d84b9eSBryan Drewery 		 * filemon lock.
330e0d84b9eSBryan Drewery 		 */
331e0d84b9eSBryan Drewery 		KASSERT(p->p_filemon == NULL || p->p_filemon == filemon,
332e0d84b9eSBryan Drewery 		    ("%s: p %p was attached while exiting, expected "
333e0d84b9eSBryan Drewery 		    "filemon %p or NULL", __func__, p, filemon));
334e0d84b9eSBryan Drewery 		if (p->p_filemon == filemon)
335e0d84b9eSBryan Drewery 			filemon_proc_drop(p);
336eb9aea5aSDavid E. O'Brien 
337e0d84b9eSBryan Drewery 		filemon_drop(filemon);
338eb9aea5aSDavid E. O'Brien 	}
339eb9aea5aSDavid E. O'Brien }
340eb9aea5aSDavid E. O'Brien 
341eb9aea5aSDavid E. O'Brien static int
filemon_wrapper_unlink(struct thread * td,struct unlink_args * uap)342eb9aea5aSDavid E. O'Brien filemon_wrapper_unlink(struct thread *td, struct unlink_args *uap)
343eb9aea5aSDavid E. O'Brien {
3449b511ce9SBryan Drewery 	int error, ret;
345eb9aea5aSDavid E. O'Brien 	struct filemon *filemon;
346eb9aea5aSDavid E. O'Brien 
347eb9aea5aSDavid E. O'Brien 	if ((ret = sys_unlink(td, uap)) == 0) {
348e0d84b9eSBryan Drewery 		if ((filemon = filemon_proc_get(curproc)) != NULL) {
3499b511ce9SBryan Drewery 			if ((error = copyinstr(uap->path, filemon->fname1,
3509b511ce9SBryan Drewery 			    sizeof(filemon->fname1), NULL)) != 0) {
3519b511ce9SBryan Drewery 				filemon->error = error;
3529b511ce9SBryan Drewery 				goto copyfail;
3539b511ce9SBryan Drewery 			}
354eb9aea5aSDavid E. O'Brien 
355bc0d7285SBryan Drewery 			filemon_output_event(filemon, "D %d %s\n",
356eb9aea5aSDavid E. O'Brien 			    curproc->p_pid, filemon->fname1);
3579b511ce9SBryan Drewery copyfail:
358e0d84b9eSBryan Drewery 			filemon_drop(filemon);
359eb9aea5aSDavid E. O'Brien 		}
360eb9aea5aSDavid E. O'Brien 	}
361eb9aea5aSDavid E. O'Brien 
362eb9aea5aSDavid E. O'Brien 	return (ret);
363eb9aea5aSDavid E. O'Brien }
364eb9aea5aSDavid E. O'Brien 
3652f600962SBryan Drewery static void
filemon_event_process_fork(void * arg __unused,struct proc * p1,struct proc * p2,int flags __unused)3662f600962SBryan Drewery filemon_event_process_fork(void *arg __unused, struct proc *p1,
367e95c55e5SBryan Drewery     struct proc *p2, int flags __unused)
368eb9aea5aSDavid E. O'Brien {
369eb9aea5aSDavid E. O'Brien 	struct filemon *filemon;
370eb9aea5aSDavid E. O'Brien 
371e0d84b9eSBryan Drewery 	if ((filemon = filemon_proc_get(p1)) != NULL) {
372bc0d7285SBryan Drewery 		filemon_output_event(filemon, "F %d %d\n",
3732f600962SBryan Drewery 		    p1->p_pid, p2->p_pid);
374eb9aea5aSDavid E. O'Brien 
375e0d84b9eSBryan Drewery 		/*
376e0d84b9eSBryan Drewery 		 * filemon_untrack_processes() or
377e0d84b9eSBryan Drewery 		 * filemon_ioctl(FILEMON_SET_PID) may have changed the parent's
378e0d84b9eSBryan Drewery 		 * p_filemon while in filemon_proc_get() before acquiring the
379e0d84b9eSBryan Drewery 		 * filemon lock.  Only inherit if the parent is still traced by
380e0d84b9eSBryan Drewery 		 * this filemon.
381e0d84b9eSBryan Drewery 		 */
382e0d84b9eSBryan Drewery 		if (p1->p_filemon == filemon) {
383e0d84b9eSBryan Drewery 			PROC_LOCK(p2);
384e0d84b9eSBryan Drewery 			/*
385e0d84b9eSBryan Drewery 			 * It may have been attached to already by a new
386e0d84b9eSBryan Drewery 			 * filemon.
387e0d84b9eSBryan Drewery 			 */
388e0d84b9eSBryan Drewery 			if (p2->p_filemon == NULL) {
389e0d84b9eSBryan Drewery 				p2->p_filemon = filemon_acquire(filemon);
390e0d84b9eSBryan Drewery 				++filemon->proccnt;
391e0d84b9eSBryan Drewery 			}
392e0d84b9eSBryan Drewery 			PROC_UNLOCK(p2);
393e0d84b9eSBryan Drewery 		}
394e0d84b9eSBryan Drewery 
395e0d84b9eSBryan Drewery 		filemon_drop(filemon);
396eb9aea5aSDavid E. O'Brien 	}
397eb9aea5aSDavid E. O'Brien }
398eb9aea5aSDavid E. O'Brien 
399eb9aea5aSDavid E. O'Brien static void
filemon_wrapper_install(void)400eb9aea5aSDavid E. O'Brien filemon_wrapper_install(void)
401eb9aea5aSDavid E. O'Brien {
402eb9aea5aSDavid E. O'Brien 
40366afa415SBryan Drewery 	sysent[SYS_chdir].sy_call = (sy_call_t *) filemon_wrapper_chdir;
40466afa415SBryan Drewery 	sysent[SYS_open].sy_call = (sy_call_t *) filemon_wrapper_open;
40566afa415SBryan Drewery 	sysent[SYS_openat].sy_call = (sy_call_t *) filemon_wrapper_openat;
40666afa415SBryan Drewery 	sysent[SYS_rename].sy_call = (sy_call_t *) filemon_wrapper_rename;
40766afa415SBryan Drewery 	sysent[SYS_unlink].sy_call = (sy_call_t *) filemon_wrapper_unlink;
40866afa415SBryan Drewery 	sysent[SYS_link].sy_call = (sy_call_t *) filemon_wrapper_link;
40966afa415SBryan Drewery 	sysent[SYS_symlink].sy_call = (sy_call_t *) filemon_wrapper_symlink;
41066afa415SBryan Drewery 	sysent[SYS_linkat].sy_call = (sy_call_t *) filemon_wrapper_linkat;
411eb9aea5aSDavid E. O'Brien 
4126c37a3d4SBryan Drewery #if defined(COMPAT_FREEBSD32)
41366afa415SBryan Drewery 	freebsd32_sysent[FREEBSD32_SYS_chdir].sy_call = (sy_call_t *) filemon_wrapper_chdir;
41466afa415SBryan Drewery 	freebsd32_sysent[FREEBSD32_SYS_open].sy_call = (sy_call_t *) filemon_wrapper_open;
41566afa415SBryan Drewery 	freebsd32_sysent[FREEBSD32_SYS_openat].sy_call = (sy_call_t *) filemon_wrapper_openat;
41666afa415SBryan Drewery 	freebsd32_sysent[FREEBSD32_SYS_rename].sy_call = (sy_call_t *) filemon_wrapper_rename;
41766afa415SBryan Drewery 	freebsd32_sysent[FREEBSD32_SYS_unlink].sy_call = (sy_call_t *) filemon_wrapper_unlink;
41866afa415SBryan Drewery 	freebsd32_sysent[FREEBSD32_SYS_link].sy_call = (sy_call_t *) filemon_wrapper_link;
41966afa415SBryan Drewery 	freebsd32_sysent[FREEBSD32_SYS_symlink].sy_call = (sy_call_t *) filemon_wrapper_symlink;
42066afa415SBryan Drewery 	freebsd32_sysent[FREEBSD32_SYS_linkat].sy_call = (sy_call_t *) filemon_wrapper_linkat;
4216c37a3d4SBryan Drewery #endif	/* COMPAT_FREEBSD32 */
42279d69913SBryan Drewery 
423f889a61aSBryan Drewery 	filemon_exec_tag = EVENTHANDLER_REGISTER(process_exec,
424f889a61aSBryan Drewery 	    filemon_event_process_exec, NULL, EVENTHANDLER_PRI_LAST);
42579d69913SBryan Drewery 	filemon_exit_tag = EVENTHANDLER_REGISTER(process_exit,
42679d69913SBryan Drewery 	    filemon_event_process_exit, NULL, EVENTHANDLER_PRI_LAST);
4272f600962SBryan Drewery 	filemon_fork_tag = EVENTHANDLER_REGISTER(process_fork,
4282f600962SBryan Drewery 	    filemon_event_process_fork, NULL, EVENTHANDLER_PRI_LAST);
429eb9aea5aSDavid E. O'Brien }
430eb9aea5aSDavid E. O'Brien 
431eb9aea5aSDavid E. O'Brien static void
filemon_wrapper_deinstall(void)432eb9aea5aSDavid E. O'Brien filemon_wrapper_deinstall(void)
433eb9aea5aSDavid E. O'Brien {
434eb9aea5aSDavid E. O'Brien 
43566afa415SBryan Drewery 	sysent[SYS_chdir].sy_call = (sy_call_t *)sys_chdir;
43666afa415SBryan Drewery 	sysent[SYS_open].sy_call = (sy_call_t *)sys_open;
43766afa415SBryan Drewery 	sysent[SYS_openat].sy_call = (sy_call_t *)sys_openat;
43866afa415SBryan Drewery 	sysent[SYS_rename].sy_call = (sy_call_t *)sys_rename;
43966afa415SBryan Drewery 	sysent[SYS_unlink].sy_call = (sy_call_t *)sys_unlink;
44066afa415SBryan Drewery 	sysent[SYS_link].sy_call = (sy_call_t *)sys_link;
44166afa415SBryan Drewery 	sysent[SYS_symlink].sy_call = (sy_call_t *)sys_symlink;
44266afa415SBryan Drewery 	sysent[SYS_linkat].sy_call = (sy_call_t *)sys_linkat;
443eb9aea5aSDavid E. O'Brien 
4446c37a3d4SBryan Drewery #if defined(COMPAT_FREEBSD32)
44566afa415SBryan Drewery 	freebsd32_sysent[FREEBSD32_SYS_chdir].sy_call = (sy_call_t *)sys_chdir;
44666afa415SBryan Drewery 	freebsd32_sysent[FREEBSD32_SYS_open].sy_call = (sy_call_t *)sys_open;
44766afa415SBryan Drewery 	freebsd32_sysent[FREEBSD32_SYS_openat].sy_call = (sy_call_t *)sys_openat;
44866afa415SBryan Drewery 	freebsd32_sysent[FREEBSD32_SYS_rename].sy_call = (sy_call_t *)sys_rename;
44966afa415SBryan Drewery 	freebsd32_sysent[FREEBSD32_SYS_unlink].sy_call = (sy_call_t *)sys_unlink;
45066afa415SBryan Drewery 	freebsd32_sysent[FREEBSD32_SYS_link].sy_call = (sy_call_t *)sys_link;
45166afa415SBryan Drewery 	freebsd32_sysent[FREEBSD32_SYS_symlink].sy_call = (sy_call_t *)sys_symlink;
45266afa415SBryan Drewery 	freebsd32_sysent[FREEBSD32_SYS_linkat].sy_call = (sy_call_t *)sys_linkat;
4536c37a3d4SBryan Drewery #endif	/* COMPAT_FREEBSD32 */
45479d69913SBryan Drewery 
455f889a61aSBryan Drewery 	EVENTHANDLER_DEREGISTER(process_exec, filemon_exec_tag);
45679d69913SBryan Drewery 	EVENTHANDLER_DEREGISTER(process_exit, filemon_exit_tag);
4572f600962SBryan Drewery 	EVENTHANDLER_DEREGISTER(process_fork, filemon_fork_tag);
458eb9aea5aSDavid E. O'Brien }
459