2 * Copyright (c) 2011, David E. O'Brien.
3 * Copyright (c) 2009-2011, Juniper Networks, Inc.
4 * Copyright (c) 2015, EMC Corp.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY JUNIPER NETWORKS AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL JUNIPER NETWORKS OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
32 #include <sys/imgact.h>
33 #include <sys/eventhandler.h>
35 #include <sys/vnode.h>
37 #include "opt_compat.h"
39 static eventhandler_tag filemon_exec_tag;
40 static eventhandler_tag filemon_exit_tag;
41 static eventhandler_tag filemon_fork_tag;
44 filemon_output(struct filemon *filemon, char *msg, size_t len)
49 if (filemon->fp == NULL)
57 auio.uio_segflg = UIO_SYSSPACE;
58 auio.uio_rw = UIO_WRITE;
59 auio.uio_td = curthread;
60 auio.uio_offset = (off_t) -1;
62 if (filemon->fp->f_type == DTYPE_VNODE)
65 fo_write(filemon->fp, &auio, curthread->td_ucred, 0, curthread);
68 static struct filemon *
69 filemon_pid_check(struct proc *p)
71 struct filemon *filemon;
74 if (TAILQ_EMPTY(&filemons_inuse)) {
75 filemon_unlock_read();
78 sx_slock(&proctree_lock);
79 while (p->p_pid != 0) {
80 TAILQ_FOREACH(filemon, &filemons_inuse, link) {
81 if (p == filemon->p) {
82 sx_sunlock(&proctree_lock);
83 sx_xlock(&filemon->lock);
84 filemon_unlock_read();
88 p = proc_realparent(p);
90 sx_sunlock(&proctree_lock);
91 filemon_unlock_read();
96 filemon_wrapper_chdir(struct thread *td, struct chdir_args *uap)
101 struct filemon *filemon;
103 if ((ret = sys_chdir(td, uap)) == 0) {
104 if ((filemon = filemon_pid_check(curproc)) != NULL) {
105 copyinstr(uap->path, filemon->fname1,
106 sizeof(filemon->fname1), &done);
108 len = snprintf(filemon->msgbufr,
109 sizeof(filemon->msgbufr), "C %d %s\n",
110 curproc->p_pid, filemon->fname1);
112 filemon_output(filemon, filemon->msgbufr, len);
114 sx_xunlock(&filemon->lock);
122 filemon_event_process_exec(void *arg __unused, struct proc *p,
123 struct image_params *imgp)
125 struct filemon *filemon;
126 char *fullpath, *freepath;
129 if ((filemon = filemon_pid_check(p)) != NULL) {
130 fullpath = "<unknown>";
133 vn_fullpath(FIRST_THREAD_IN_PROC(p), imgp->vp, &fullpath,
136 len = snprintf(filemon->msgbufr,
137 sizeof(filemon->msgbufr), "E %d %s\n",
140 filemon_output(filemon, filemon->msgbufr, len);
142 sx_xunlock(&filemon->lock);
144 free(freepath, M_TEMP);
149 filemon_wrapper_open(struct thread *td, struct open_args *uap)
154 struct filemon *filemon;
156 if ((ret = sys_open(td, uap)) == 0) {
157 if ((filemon = filemon_pid_check(curproc)) != NULL) {
158 copyinstr(uap->path, filemon->fname1,
159 sizeof(filemon->fname1), &done);
161 if (uap->flags & O_RDWR) {
163 * We'll get the W record below, but need
164 * to also output an R to distingish from
167 len = snprintf(filemon->msgbufr,
168 sizeof(filemon->msgbufr), "R %d %s\n",
169 curproc->p_pid, filemon->fname1);
170 filemon_output(filemon, filemon->msgbufr, len);
174 len = snprintf(filemon->msgbufr,
175 sizeof(filemon->msgbufr), "%c %d %s\n",
176 (uap->flags & O_ACCMODE) ? 'W':'R',
177 curproc->p_pid, filemon->fname1);
178 filemon_output(filemon, filemon->msgbufr, len);
180 sx_xunlock(&filemon->lock);
188 filemon_wrapper_openat(struct thread *td, struct openat_args *uap)
193 struct filemon *filemon;
195 if ((ret = sys_openat(td, uap)) == 0) {
196 if ((filemon = filemon_pid_check(curproc)) != NULL) {
197 copyinstr(uap->path, filemon->fname1,
198 sizeof(filemon->fname1), &done);
200 filemon->fname2[0] = '\0';
201 if (filemon->fname1[0] != '/' && uap->fd != AT_FDCWD) {
203 * rats - we cannot do too much about this.
204 * the trace should show a dir we read
205 * recently.. output an A record as a clue
206 * until we can do better.
208 len = snprintf(filemon->msgbufr,
209 sizeof(filemon->msgbufr), "A %d %s\n",
210 curproc->p_pid, filemon->fname1);
211 filemon_output(filemon, filemon->msgbufr, len);
213 if (uap->flag & O_RDWR) {
215 * We'll get the W record below, but need
216 * to also output an R to distingish from
219 len = snprintf(filemon->msgbufr,
220 sizeof(filemon->msgbufr), "R %d %s%s\n",
221 curproc->p_pid, filemon->fname2, filemon->fname1);
222 filemon_output(filemon, filemon->msgbufr, len);
226 len = snprintf(filemon->msgbufr,
227 sizeof(filemon->msgbufr), "%c %d %s%s\n",
228 (uap->flag & O_ACCMODE) ? 'W':'R',
229 curproc->p_pid, filemon->fname2, filemon->fname1);
230 filemon_output(filemon, filemon->msgbufr, len);
232 sx_xunlock(&filemon->lock);
240 filemon_wrapper_rename(struct thread *td, struct rename_args *uap)
245 struct filemon *filemon;
247 if ((ret = sys_rename(td, uap)) == 0) {
248 if ((filemon = filemon_pid_check(curproc)) != NULL) {
249 copyinstr(uap->from, filemon->fname1,
250 sizeof(filemon->fname1), &done);
251 copyinstr(uap->to, filemon->fname2,
252 sizeof(filemon->fname2), &done);
254 len = snprintf(filemon->msgbufr,
255 sizeof(filemon->msgbufr), "M %d '%s' '%s'\n",
256 curproc->p_pid, filemon->fname1, filemon->fname2);
258 filemon_output(filemon, filemon->msgbufr, len);
260 sx_xunlock(&filemon->lock);
268 filemon_wrapper_link(struct thread *td, struct link_args *uap)
273 struct filemon *filemon;
275 if ((ret = sys_link(td, uap)) == 0) {
276 if ((filemon = filemon_pid_check(curproc)) != NULL) {
277 copyinstr(uap->path, filemon->fname1,
278 sizeof(filemon->fname1), &done);
279 copyinstr(uap->link, filemon->fname2,
280 sizeof(filemon->fname2), &done);
282 len = snprintf(filemon->msgbufr,
283 sizeof(filemon->msgbufr), "L %d '%s' '%s'\n",
284 curproc->p_pid, filemon->fname1, filemon->fname2);
286 filemon_output(filemon, filemon->msgbufr, len);
288 sx_xunlock(&filemon->lock);
296 filemon_wrapper_symlink(struct thread *td, struct symlink_args *uap)
301 struct filemon *filemon;
303 if ((ret = sys_symlink(td, uap)) == 0) {
304 if ((filemon = filemon_pid_check(curproc)) != NULL) {
305 copyinstr(uap->path, filemon->fname1,
306 sizeof(filemon->fname1), &done);
307 copyinstr(uap->link, filemon->fname2,
308 sizeof(filemon->fname2), &done);
310 len = snprintf(filemon->msgbufr,
311 sizeof(filemon->msgbufr), "L %d '%s' '%s'\n",
312 curproc->p_pid, filemon->fname1, filemon->fname2);
314 filemon_output(filemon, filemon->msgbufr, len);
316 sx_xunlock(&filemon->lock);
324 filemon_wrapper_linkat(struct thread *td, struct linkat_args *uap)
329 struct filemon *filemon;
331 if ((ret = sys_linkat(td, uap)) == 0) {
332 if ((filemon = filemon_pid_check(curproc)) != NULL) {
333 copyinstr(uap->path1, filemon->fname1,
334 sizeof(filemon->fname1), &done);
335 copyinstr(uap->path2, filemon->fname2,
336 sizeof(filemon->fname2), &done);
338 len = snprintf(filemon->msgbufr,
339 sizeof(filemon->msgbufr), "L %d '%s' '%s'\n",
340 curproc->p_pid, filemon->fname1, filemon->fname2);
342 filemon_output(filemon, filemon->msgbufr, len);
344 sx_xunlock(&filemon->lock);
352 filemon_wrapper_stat(struct thread *td, struct stat_args *uap)
357 struct filemon *filemon;
359 if ((ret = sys_stat(td, uap)) == 0) {
360 if ((filemon = filemon_pid_check(curproc)) != NULL) {
361 copyinstr(uap->path, filemon->fname1,
362 sizeof(filemon->fname1), &done);
364 len = snprintf(filemon->msgbufr,
365 sizeof(filemon->msgbufr), "S %d %s\n",
366 curproc->p_pid, filemon->fname1);
368 filemon_output(filemon, filemon->msgbufr, len);
370 sx_xunlock(&filemon->lock);
377 #if defined(COMPAT_IA32) || defined(COMPAT_FREEBSD32) || defined(COMPAT_ARCH32)
379 filemon_wrapper_freebsd32_stat(struct thread *td,
380 struct freebsd32_stat_args *uap)
385 struct filemon *filemon;
387 if ((ret = freebsd32_stat(td, uap)) == 0) {
388 if ((filemon = filemon_pid_check(curproc)) != NULL) {
389 copyinstr(uap->path, filemon->fname1,
390 sizeof(filemon->fname1), &done);
392 len = snprintf(filemon->msgbufr,
393 sizeof(filemon->msgbufr), "S %d %s\n",
394 curproc->p_pid, filemon->fname1);
396 filemon_output(filemon, filemon->msgbufr, len);
398 sx_xunlock(&filemon->lock);
407 filemon_event_process_exit(void *arg __unused, struct proc *p)
410 struct filemon *filemon;
413 /* Get timestamp before locking. */
416 if ((filemon = filemon_pid_check(p)) != NULL) {
417 len = snprintf(filemon->msgbufr, sizeof(filemon->msgbufr),
418 "X %d %d\n", p->p_pid, W_EXITCODE(p->p_xstat, 0));
420 filemon_output(filemon, filemon->msgbufr, len);
422 /* Check if the monitored process is about to exit. */
423 if (filemon->p == p) {
424 len = snprintf(filemon->msgbufr,
425 sizeof(filemon->msgbufr),
426 "# Stop %ju.%06ju\n# Bye bye\n",
427 (uintmax_t)now.tv_sec, (uintmax_t)now.tv_usec);
429 filemon_output(filemon, filemon->msgbufr, len);
433 sx_xunlock(&filemon->lock);
438 filemon_wrapper_unlink(struct thread *td, struct unlink_args *uap)
443 struct filemon *filemon;
445 if ((ret = sys_unlink(td, uap)) == 0) {
446 if ((filemon = filemon_pid_check(curproc)) != NULL) {
447 copyinstr(uap->path, filemon->fname1,
448 sizeof(filemon->fname1), &done);
450 len = snprintf(filemon->msgbufr,
451 sizeof(filemon->msgbufr), "D %d %s\n",
452 curproc->p_pid, filemon->fname1);
454 filemon_output(filemon, filemon->msgbufr, len);
456 sx_xunlock(&filemon->lock);
464 filemon_event_process_fork(void *arg __unused, struct proc *p1,
465 struct proc *p2, int flags __unused)
468 struct filemon *filemon;
470 if ((filemon = filemon_pid_check(p1)) != NULL) {
471 len = snprintf(filemon->msgbufr,
472 sizeof(filemon->msgbufr), "F %d %d\n",
473 p1->p_pid, p2->p_pid);
475 filemon_output(filemon, filemon->msgbufr, len);
477 sx_xunlock(&filemon->lock);
482 filemon_wrapper_install(void)
484 #if defined(__i386__)
485 struct sysent *sv_table = elf32_freebsd_sysvec.sv_table;
486 #elif defined(__amd64__)
487 struct sysent *sv_table = elf64_freebsd_sysvec.sv_table;
489 #error Machine type not supported
492 sv_table[SYS_chdir].sy_call = (sy_call_t *) filemon_wrapper_chdir;
493 sv_table[SYS_open].sy_call = (sy_call_t *) filemon_wrapper_open;
494 sv_table[SYS_openat].sy_call = (sy_call_t *) filemon_wrapper_openat;
495 sv_table[SYS_rename].sy_call = (sy_call_t *) filemon_wrapper_rename;
496 sv_table[SYS_stat].sy_call = (sy_call_t *) filemon_wrapper_stat;
497 sv_table[SYS_unlink].sy_call = (sy_call_t *) filemon_wrapper_unlink;
498 sv_table[SYS_link].sy_call = (sy_call_t *) filemon_wrapper_link;
499 sv_table[SYS_symlink].sy_call = (sy_call_t *) filemon_wrapper_symlink;
500 sv_table[SYS_linkat].sy_call = (sy_call_t *) filemon_wrapper_linkat;
502 #if defined(COMPAT_IA32) || defined(COMPAT_FREEBSD32) || defined(COMPAT_ARCH32)
503 sv_table = ia32_freebsd_sysvec.sv_table;
505 sv_table[FREEBSD32_SYS_chdir].sy_call = (sy_call_t *) filemon_wrapper_chdir;
506 sv_table[FREEBSD32_SYS_open].sy_call = (sy_call_t *) filemon_wrapper_open;
507 sv_table[FREEBSD32_SYS_openat].sy_call = (sy_call_t *) filemon_wrapper_openat;
508 sv_table[FREEBSD32_SYS_rename].sy_call = (sy_call_t *) filemon_wrapper_rename;
509 sv_table[FREEBSD32_SYS_freebsd32_stat].sy_call = (sy_call_t *) filemon_wrapper_freebsd32_stat;
510 sv_table[FREEBSD32_SYS_unlink].sy_call = (sy_call_t *) filemon_wrapper_unlink;
511 sv_table[FREEBSD32_SYS_link].sy_call = (sy_call_t *) filemon_wrapper_link;
512 sv_table[FREEBSD32_SYS_symlink].sy_call = (sy_call_t *) filemon_wrapper_symlink;
513 sv_table[FREEBSD32_SYS_linkat].sy_call = (sy_call_t *) filemon_wrapper_linkat;
514 #endif /* COMPAT_ARCH32 */
516 filemon_exec_tag = EVENTHANDLER_REGISTER(process_exec,
517 filemon_event_process_exec, NULL, EVENTHANDLER_PRI_LAST);
518 filemon_exit_tag = EVENTHANDLER_REGISTER(process_exit,
519 filemon_event_process_exit, NULL, EVENTHANDLER_PRI_LAST);
520 filemon_fork_tag = EVENTHANDLER_REGISTER(process_fork,
521 filemon_event_process_fork, NULL, EVENTHANDLER_PRI_LAST);
525 filemon_wrapper_deinstall(void)
527 #if defined(__i386__)
528 struct sysent *sv_table = elf32_freebsd_sysvec.sv_table;
529 #elif defined(__amd64__)
530 struct sysent *sv_table = elf64_freebsd_sysvec.sv_table;
532 #error Machine type not supported
535 sv_table[SYS_chdir].sy_call = (sy_call_t *)sys_chdir;
536 sv_table[SYS_open].sy_call = (sy_call_t *)sys_open;
537 sv_table[SYS_openat].sy_call = (sy_call_t *)sys_openat;
538 sv_table[SYS_rename].sy_call = (sy_call_t *)sys_rename;
539 sv_table[SYS_stat].sy_call = (sy_call_t *)sys_stat;
540 sv_table[SYS_unlink].sy_call = (sy_call_t *)sys_unlink;
541 sv_table[SYS_link].sy_call = (sy_call_t *)sys_link;
542 sv_table[SYS_symlink].sy_call = (sy_call_t *)sys_symlink;
543 sv_table[SYS_linkat].sy_call = (sy_call_t *)sys_linkat;
545 #if defined(COMPAT_IA32) || defined(COMPAT_FREEBSD32) || defined(COMPAT_ARCH32)
546 sv_table = ia32_freebsd_sysvec.sv_table;
548 sv_table[FREEBSD32_SYS_chdir].sy_call = (sy_call_t *)sys_chdir;
549 sv_table[FREEBSD32_SYS_open].sy_call = (sy_call_t *)sys_open;
550 sv_table[FREEBSD32_SYS_openat].sy_call = (sy_call_t *)sys_openat;
551 sv_table[FREEBSD32_SYS_rename].sy_call = (sy_call_t *)sys_rename;
552 sv_table[FREEBSD32_SYS_freebsd32_stat].sy_call = (sy_call_t *)freebsd32_stat;
553 sv_table[FREEBSD32_SYS_unlink].sy_call = (sy_call_t *)sys_unlink;
554 sv_table[FREEBSD32_SYS_link].sy_call = (sy_call_t *)sys_link;
555 sv_table[FREEBSD32_SYS_symlink].sy_call = (sy_call_t *)sys_symlink;
556 sv_table[FREEBSD32_SYS_linkat].sy_call = (sy_call_t *)sys_linkat;
557 #endif /* COMPAT_ARCH32 */
559 EVENTHANDLER_DEREGISTER(process_exec, filemon_exec_tag);
560 EVENTHANDLER_DEREGISTER(process_exit, filemon_exit_tag);
561 EVENTHANDLER_DEREGISTER(process_fork, filemon_fork_tag);