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$");
34 #include "opt_compat.h"
36 #if __FreeBSD_version > 800032
37 #define FILEMON_HAS_LINKAT
40 #if __FreeBSD_version < 900044 /* r225617 (2011-09-16) failed to bump
41 __FreeBSD_version. This really should
42 be based on "900045". "900044" is r225469
43 (2011-09-10) so this code is broken for
44 9-CURRENT September 10th-16th. */
45 #define sys_chdir chdir
46 #define sys_execve execve
50 #define sys_rename rename
52 #define sys_symlink symlink
53 #define sys_unlink unlink
54 #define sys_vfork vfork
55 #define sys_sys_exit sys_exit
56 #ifdef FILEMON_HAS_LINKAT
57 #define sys_linkat linkat
59 #endif /* __FreeBSD_version */
62 filemon_output(struct filemon *filemon, char *msg, size_t len)
67 if (filemon->fp == NULL)
75 auio.uio_segflg = UIO_SYSSPACE;
76 auio.uio_rw = UIO_WRITE;
77 auio.uio_td = curthread;
78 auio.uio_offset = (off_t) -1;
82 fo_write(filemon->fp, &auio, curthread->td_ucred, 0, curthread);
85 static struct filemon *
86 filemon_pid_check(struct proc *p)
88 struct filemon *filemon;
91 if (TAILQ_EMPTY(&filemons_inuse)) {
92 filemon_unlock_read();
95 sx_slock(&proctree_lock);
96 while (p != initproc) {
97 TAILQ_FOREACH(filemon, &filemons_inuse, link) {
98 if (p->p_pid == filemon->pid) {
99 sx_sunlock(&proctree_lock);
100 filemon_filemon_lock(filemon);
101 filemon_unlock_read();
105 p = proc_realparent(p);
107 sx_sunlock(&proctree_lock);
108 filemon_unlock_read();
113 filemon_comment(struct filemon *filemon)
118 /* Load timestamp before locking. Less accurate but less contention. */
121 /* Lock the found filemon structure. */
122 filemon_filemon_lock(filemon);
124 len = snprintf(filemon->msgbufr, sizeof(filemon->msgbufr),
125 "# filemon version %d\n# Target pid %d\n# Start %ju.%06ju\nV %d\n",
126 FILEMON_VERSION, curproc->p_pid, (uintmax_t)now.tv_sec,
127 (uintmax_t)now.tv_usec, FILEMON_VERSION);
129 filemon_output(filemon, filemon->msgbufr, len);
131 /* Unlock the found filemon structure. */
132 filemon_filemon_unlock(filemon);
136 filemon_wrapper_chdir(struct thread *td, struct chdir_args *uap)
141 struct filemon *filemon;
143 if ((ret = sys_chdir(td, uap)) == 0) {
144 if ((filemon = filemon_pid_check(curproc)) != NULL) {
145 copyinstr(uap->path, filemon->fname1,
146 sizeof(filemon->fname1), &done);
148 len = snprintf(filemon->msgbufr,
149 sizeof(filemon->msgbufr), "C %d %s\n",
150 curproc->p_pid, filemon->fname1);
152 filemon_output(filemon, filemon->msgbufr, len);
154 /* Unlock the found filemon structure. */
155 filemon_filemon_unlock(filemon);
163 filemon_wrapper_execve(struct thread *td, struct execve_args *uap)
165 char fname[MAXPATHLEN];
169 struct filemon *filemon;
171 copyinstr(uap->fname, fname, sizeof(fname), &done);
173 if ((ret = sys_execve(td, uap)) == 0) {
174 if ((filemon = filemon_pid_check(curproc)) != NULL) {
175 len = snprintf(filemon->msgbufr,
176 sizeof(filemon->msgbufr), "E %d %s\n",
177 curproc->p_pid, fname);
179 filemon_output(filemon, filemon->msgbufr, len);
181 /* Unlock the found filemon structure. */
182 filemon_filemon_unlock(filemon);
189 #if defined(COMPAT_IA32) || defined(COMPAT_FREEBSD32) || defined(COMPAT_ARCH32)
191 filemon_wrapper_freebsd32_execve(struct thread *td,
192 struct freebsd32_execve_args *uap)
194 char fname[MAXPATHLEN];
198 struct filemon *filemon;
200 copyinstr(uap->fname, fname, sizeof(fname), &done);
202 if ((ret = freebsd32_execve(td, uap)) == 0) {
203 if ((filemon = filemon_pid_check(curproc)) != NULL) {
204 len = snprintf(filemon->msgbufr,
205 sizeof(filemon->msgbufr), "E %d %s\n",
206 curproc->p_pid, fname);
208 filemon_output(filemon, filemon->msgbufr, len);
210 /* Unlock the found filemon structure. */
211 filemon_filemon_unlock(filemon);
220 filemon_wrapper_fork(struct thread *td, struct fork_args *uap)
224 struct filemon *filemon;
226 if ((ret = sys_fork(td, uap)) == 0) {
227 if ((filemon = filemon_pid_check(curproc)) != NULL) {
228 len = snprintf(filemon->msgbufr,
229 sizeof(filemon->msgbufr), "F %d %ld\n",
230 curproc->p_pid, (long)curthread->td_retval[0]);
232 filemon_output(filemon, filemon->msgbufr, len);
234 /* Unlock the found filemon structure. */
235 filemon_filemon_unlock(filemon);
243 filemon_wrapper_open(struct thread *td, struct open_args *uap)
248 struct filemon *filemon;
250 if ((ret = sys_open(td, uap)) == 0) {
251 if ((filemon = filemon_pid_check(curproc)) != NULL) {
252 copyinstr(uap->path, filemon->fname1,
253 sizeof(filemon->fname1), &done);
255 if (uap->flags & O_RDWR) {
257 * We'll get the W record below, but need
258 * to also output an R to distingish from
261 len = snprintf(filemon->msgbufr,
262 sizeof(filemon->msgbufr), "R %d %s\n",
263 curproc->p_pid, filemon->fname1);
264 filemon_output(filemon, filemon->msgbufr, len);
268 len = snprintf(filemon->msgbufr,
269 sizeof(filemon->msgbufr), "%c %d %s\n",
270 (uap->flags & O_ACCMODE) ? 'W':'R',
271 curproc->p_pid, filemon->fname1);
272 filemon_output(filemon, filemon->msgbufr, len);
274 /* Unlock the found filemon structure. */
275 filemon_filemon_unlock(filemon);
283 filemon_wrapper_openat(struct thread *td, struct openat_args *uap)
288 struct filemon *filemon;
290 if ((ret = sys_openat(td, uap)) == 0) {
291 if ((filemon = filemon_pid_check(curproc)) != NULL) {
292 copyinstr(uap->path, filemon->fname1,
293 sizeof(filemon->fname1), &done);
295 filemon->fname2[0] = '\0';
296 if (filemon->fname1[0] != '/' && uap->fd != AT_FDCWD) {
298 * rats - we cannot do too much about this.
299 * the trace should show a dir we read
300 * recently.. output an A record as a clue
301 * until we can do better.
303 len = snprintf(filemon->msgbufr,
304 sizeof(filemon->msgbufr), "A %d %s\n",
305 curproc->p_pid, filemon->fname1);
306 filemon_output(filemon, filemon->msgbufr, len);
308 if (uap->flag & O_RDWR) {
310 * We'll get the W record below, but need
311 * to also output an R to distingish from
314 len = snprintf(filemon->msgbufr,
315 sizeof(filemon->msgbufr), "R %d %s%s\n",
316 curproc->p_pid, filemon->fname2, filemon->fname1);
317 filemon_output(filemon, filemon->msgbufr, len);
321 len = snprintf(filemon->msgbufr,
322 sizeof(filemon->msgbufr), "%c %d %s%s\n",
323 (uap->flag & O_ACCMODE) ? 'W':'R',
324 curproc->p_pid, filemon->fname2, filemon->fname1);
325 filemon_output(filemon, filemon->msgbufr, len);
327 /* Unlock the found filemon structure. */
328 filemon_filemon_unlock(filemon);
336 filemon_wrapper_rename(struct thread *td, struct rename_args *uap)
341 struct filemon *filemon;
343 if ((ret = sys_rename(td, uap)) == 0) {
344 if ((filemon = filemon_pid_check(curproc)) != NULL) {
345 copyinstr(uap->from, filemon->fname1,
346 sizeof(filemon->fname1), &done);
347 copyinstr(uap->to, filemon->fname2,
348 sizeof(filemon->fname2), &done);
350 len = snprintf(filemon->msgbufr,
351 sizeof(filemon->msgbufr), "M %d '%s' '%s'\n",
352 curproc->p_pid, filemon->fname1, filemon->fname2);
354 filemon_output(filemon, filemon->msgbufr, len);
356 /* Unlock the found filemon structure. */
357 filemon_filemon_unlock(filemon);
365 filemon_wrapper_link(struct thread *td, struct link_args *uap)
370 struct filemon *filemon;
372 if ((ret = sys_link(td, uap)) == 0) {
373 if ((filemon = filemon_pid_check(curproc)) != NULL) {
374 copyinstr(uap->path, filemon->fname1,
375 sizeof(filemon->fname1), &done);
376 copyinstr(uap->link, filemon->fname2,
377 sizeof(filemon->fname2), &done);
379 len = snprintf(filemon->msgbufr,
380 sizeof(filemon->msgbufr), "L %d '%s' '%s'\n",
381 curproc->p_pid, filemon->fname1, filemon->fname2);
383 filemon_output(filemon, filemon->msgbufr, len);
385 /* Unlock the found filemon structure. */
386 filemon_filemon_unlock(filemon);
394 filemon_wrapper_symlink(struct thread *td, struct symlink_args *uap)
399 struct filemon *filemon;
401 if ((ret = sys_symlink(td, uap)) == 0) {
402 if ((filemon = filemon_pid_check(curproc)) != NULL) {
403 copyinstr(uap->path, filemon->fname1,
404 sizeof(filemon->fname1), &done);
405 copyinstr(uap->link, filemon->fname2,
406 sizeof(filemon->fname2), &done);
408 len = snprintf(filemon->msgbufr,
409 sizeof(filemon->msgbufr), "L %d '%s' '%s'\n",
410 curproc->p_pid, filemon->fname1, filemon->fname2);
412 filemon_output(filemon, filemon->msgbufr, len);
414 /* Unlock the found filemon structure. */
415 filemon_filemon_unlock(filemon);
422 #ifdef FILEMON_HAS_LINKAT
424 filemon_wrapper_linkat(struct thread *td, struct linkat_args *uap)
429 struct filemon *filemon;
431 if ((ret = sys_linkat(td, uap)) == 0) {
432 if ((filemon = filemon_pid_check(curproc)) != NULL) {
433 copyinstr(uap->path1, filemon->fname1,
434 sizeof(filemon->fname1), &done);
435 copyinstr(uap->path2, filemon->fname2,
436 sizeof(filemon->fname2), &done);
438 len = snprintf(filemon->msgbufr,
439 sizeof(filemon->msgbufr), "L %d '%s' '%s'\n",
440 curproc->p_pid, filemon->fname1, filemon->fname2);
442 filemon_output(filemon, filemon->msgbufr, len);
444 /* Unlock the found filemon structure. */
445 filemon_filemon_unlock(filemon);
454 filemon_wrapper_stat(struct thread *td, struct stat_args *uap)
459 struct filemon *filemon;
461 if ((ret = sys_stat(td, uap)) == 0) {
462 if ((filemon = filemon_pid_check(curproc)) != NULL) {
463 copyinstr(uap->path, filemon->fname1,
464 sizeof(filemon->fname1), &done);
466 len = snprintf(filemon->msgbufr,
467 sizeof(filemon->msgbufr), "S %d %s\n",
468 curproc->p_pid, filemon->fname1);
470 filemon_output(filemon, filemon->msgbufr, len);
472 /* Unlock the found filemon structure. */
473 filemon_filemon_unlock(filemon);
480 #if defined(COMPAT_IA32) || defined(COMPAT_FREEBSD32) || defined(COMPAT_ARCH32)
482 filemon_wrapper_freebsd32_stat(struct thread *td,
483 struct freebsd32_stat_args *uap)
488 struct filemon *filemon;
490 if ((ret = freebsd32_stat(td, uap)) == 0) {
491 if ((filemon = filemon_pid_check(curproc)) != NULL) {
492 copyinstr(uap->path, filemon->fname1,
493 sizeof(filemon->fname1), &done);
495 len = snprintf(filemon->msgbufr,
496 sizeof(filemon->msgbufr), "S %d %s\n",
497 curproc->p_pid, filemon->fname1);
499 filemon_output(filemon, filemon->msgbufr, len);
501 /* Unlock the found filemon structure. */
502 filemon_filemon_unlock(filemon);
511 filemon_wrapper_sys_exit(struct thread *td, struct sys_exit_args *uap)
514 struct filemon *filemon;
517 /* Get timestamp before locking. */
520 if ((filemon = filemon_pid_check(curproc)) != NULL) {
521 len = snprintf(filemon->msgbufr, sizeof(filemon->msgbufr),
522 "X %d %d\n", curproc->p_pid, uap->rval);
524 filemon_output(filemon, filemon->msgbufr, len);
526 /* Check if the monitored process is about to exit. */
527 if (filemon->pid == curproc->p_pid) {
528 len = snprintf(filemon->msgbufr,
529 sizeof(filemon->msgbufr),
530 "# Stop %ju.%06ju\n# Bye bye\n",
531 (uintmax_t)now.tv_sec, (uintmax_t)now.tv_usec);
533 filemon_output(filemon, filemon->msgbufr, len);
537 /* Unlock the found filemon structure. */
538 filemon_filemon_unlock(filemon);
541 sys_sys_exit(td, uap);
545 filemon_wrapper_unlink(struct thread *td, struct unlink_args *uap)
550 struct filemon *filemon;
552 if ((ret = sys_unlink(td, uap)) == 0) {
553 if ((filemon = filemon_pid_check(curproc)) != NULL) {
554 copyinstr(uap->path, filemon->fname1,
555 sizeof(filemon->fname1), &done);
557 len = snprintf(filemon->msgbufr,
558 sizeof(filemon->msgbufr), "D %d %s\n",
559 curproc->p_pid, filemon->fname1);
561 filemon_output(filemon, filemon->msgbufr, len);
563 /* Unlock the found filemon structure. */
564 filemon_filemon_unlock(filemon);
572 filemon_wrapper_vfork(struct thread *td, struct vfork_args *uap)
576 struct filemon *filemon;
578 if ((ret = sys_vfork(td, uap)) == 0) {
579 if ((filemon = filemon_pid_check(curproc)) != NULL) {
580 len = snprintf(filemon->msgbufr,
581 sizeof(filemon->msgbufr), "F %d %ld\n",
582 curproc->p_pid, (long)curthread->td_retval[0]);
584 filemon_output(filemon, filemon->msgbufr, len);
586 /* Unlock the found filemon structure. */
587 filemon_filemon_unlock(filemon);
595 filemon_wrapper_install(void)
597 #if defined(__LP64__)
598 struct sysent *sv_table = elf64_freebsd_sysvec.sv_table;
600 struct sysent *sv_table = elf32_freebsd_sysvec.sv_table;
603 sv_table[SYS_chdir].sy_call = (sy_call_t *) filemon_wrapper_chdir;
604 sv_table[SYS_exit].sy_call = (sy_call_t *) filemon_wrapper_sys_exit;
605 sv_table[SYS_execve].sy_call = (sy_call_t *) filemon_wrapper_execve;
606 sv_table[SYS_fork].sy_call = (sy_call_t *) filemon_wrapper_fork;
607 sv_table[SYS_open].sy_call = (sy_call_t *) filemon_wrapper_open;
608 sv_table[SYS_openat].sy_call = (sy_call_t *) filemon_wrapper_openat;
609 sv_table[SYS_rename].sy_call = (sy_call_t *) filemon_wrapper_rename;
610 sv_table[SYS_stat].sy_call = (sy_call_t *) filemon_wrapper_stat;
611 sv_table[SYS_unlink].sy_call = (sy_call_t *) filemon_wrapper_unlink;
612 sv_table[SYS_vfork].sy_call = (sy_call_t *) filemon_wrapper_vfork;
613 sv_table[SYS_link].sy_call = (sy_call_t *) filemon_wrapper_link;
614 sv_table[SYS_symlink].sy_call = (sy_call_t *) filemon_wrapper_symlink;
615 #ifdef FILEMON_HAS_LINKAT
616 sv_table[SYS_linkat].sy_call = (sy_call_t *) filemon_wrapper_linkat;
619 #if defined(COMPAT_IA32) || defined(COMPAT_FREEBSD32) || defined(COMPAT_ARCH32)
620 sv_table = ia32_freebsd_sysvec.sv_table;
622 sv_table[FREEBSD32_SYS_chdir].sy_call = (sy_call_t *) filemon_wrapper_chdir;
623 sv_table[FREEBSD32_SYS_exit].sy_call = (sy_call_t *) filemon_wrapper_sys_exit;
624 sv_table[FREEBSD32_SYS_freebsd32_execve].sy_call = (sy_call_t *) filemon_wrapper_freebsd32_execve;
625 sv_table[FREEBSD32_SYS_fork].sy_call = (sy_call_t *) filemon_wrapper_fork;
626 sv_table[FREEBSD32_SYS_open].sy_call = (sy_call_t *) filemon_wrapper_open;
627 sv_table[FREEBSD32_SYS_openat].sy_call = (sy_call_t *) filemon_wrapper_openat;
628 sv_table[FREEBSD32_SYS_rename].sy_call = (sy_call_t *) filemon_wrapper_rename;
629 sv_table[FREEBSD32_SYS_freebsd32_stat].sy_call = (sy_call_t *) filemon_wrapper_freebsd32_stat;
630 sv_table[FREEBSD32_SYS_unlink].sy_call = (sy_call_t *) filemon_wrapper_unlink;
631 sv_table[FREEBSD32_SYS_vfork].sy_call = (sy_call_t *) filemon_wrapper_vfork;
632 sv_table[FREEBSD32_SYS_link].sy_call = (sy_call_t *) filemon_wrapper_link;
633 sv_table[FREEBSD32_SYS_symlink].sy_call = (sy_call_t *) filemon_wrapper_symlink;
634 #ifdef FILEMON_HAS_LINKAT
635 sv_table[FREEBSD32_SYS_linkat].sy_call = (sy_call_t *) filemon_wrapper_linkat;
637 #endif /* COMPAT_ARCH32 */
641 filemon_wrapper_deinstall(void)
643 #if defined(__LP64__)
644 struct sysent *sv_table = elf64_freebsd_sysvec.sv_table;
646 struct sysent *sv_table = elf32_freebsd_sysvec.sv_table;
649 sv_table[SYS_chdir].sy_call = (sy_call_t *)sys_chdir;
650 sv_table[SYS_exit].sy_call = (sy_call_t *)sys_sys_exit;
651 sv_table[SYS_execve].sy_call = (sy_call_t *)sys_execve;
652 sv_table[SYS_fork].sy_call = (sy_call_t *)sys_fork;
653 sv_table[SYS_open].sy_call = (sy_call_t *)sys_open;
654 sv_table[SYS_openat].sy_call = (sy_call_t *)sys_openat;
655 sv_table[SYS_rename].sy_call = (sy_call_t *)sys_rename;
656 sv_table[SYS_stat].sy_call = (sy_call_t *)sys_stat;
657 sv_table[SYS_unlink].sy_call = (sy_call_t *)sys_unlink;
658 sv_table[SYS_vfork].sy_call = (sy_call_t *)sys_vfork;
659 sv_table[SYS_link].sy_call = (sy_call_t *)sys_link;
660 sv_table[SYS_symlink].sy_call = (sy_call_t *)sys_symlink;
661 #ifdef FILEMON_HAS_LINKAT
662 sv_table[SYS_linkat].sy_call = (sy_call_t *)sys_linkat;
665 #if defined(COMPAT_IA32) || defined(COMPAT_FREEBSD32) || defined(COMPAT_ARCH32)
666 sv_table = ia32_freebsd_sysvec.sv_table;
668 sv_table[FREEBSD32_SYS_chdir].sy_call = (sy_call_t *)sys_chdir;
669 sv_table[FREEBSD32_SYS_exit].sy_call = (sy_call_t *)sys_sys_exit;
670 sv_table[FREEBSD32_SYS_freebsd32_execve].sy_call = (sy_call_t *)freebsd32_execve;
671 sv_table[FREEBSD32_SYS_fork].sy_call = (sy_call_t *)sys_fork;
672 sv_table[FREEBSD32_SYS_open].sy_call = (sy_call_t *)sys_open;
673 sv_table[FREEBSD32_SYS_openat].sy_call = (sy_call_t *)sys_openat;
674 sv_table[FREEBSD32_SYS_rename].sy_call = (sy_call_t *)sys_rename;
675 sv_table[FREEBSD32_SYS_freebsd32_stat].sy_call = (sy_call_t *)freebsd32_stat;
676 sv_table[FREEBSD32_SYS_unlink].sy_call = (sy_call_t *)sys_unlink;
677 sv_table[FREEBSD32_SYS_vfork].sy_call = (sy_call_t *)sys_vfork;
678 sv_table[FREEBSD32_SYS_link].sy_call = (sy_call_t *)sys_link;
679 sv_table[FREEBSD32_SYS_symlink].sy_call = (sy_call_t *)sys_symlink;
680 #ifdef FILEMON_HAS_LINKAT
681 sv_table[FREEBSD32_SYS_linkat].sy_call = (sy_call_t *)sys_linkat;
683 #endif /* COMPAT_ARCH32 */