2 * Copyright (c) 2011, David E. O'Brien.
3 * Copyright (c) 2009-2011, Juniper Networks, Inc.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY JUNIPER NETWORKS AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL JUNIPER NETWORKS OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
31 #include "opt_compat.h"
33 #if __FreeBSD_version > 800032
34 #define FILEMON_HAS_LINKAT
37 #if __FreeBSD_version < 900044 /* r225617 (2011-09-16) failed to bump
38 __FreeBSD_version. This really should
39 be based on "900045". "900044" is r225469
40 (2011-09-10) so this code is broken for
41 9-CURRENT September 10th-16th. */
42 #define sys_chdir chdir
43 #define sys_execve execve
47 #define sys_rename rename
49 #define sys_symlink symlink
50 #define sys_unlink unlink
51 #define sys_vfork vfork
52 #define sys_sys_exit sys_exit
53 #ifdef FILEMON_HAS_LINKAT
54 #define sys_linkat linkat
56 #endif /* __FreeBSD_version */
59 filemon_output(struct filemon *filemon, char *msg, size_t len)
64 if (filemon->fp == NULL)
72 auio.uio_segflg = UIO_SYSSPACE;
73 auio.uio_rw = UIO_WRITE;
74 auio.uio_td = curthread;
75 auio.uio_offset = (off_t) -1;
79 fo_write(filemon->fp, &auio, curthread->td_ucred, 0, curthread);
82 static struct filemon *
83 filemon_pid_check(struct proc *p)
85 struct filemon *filemon;
88 TAILQ_FOREACH(filemon, &filemons_inuse, link) {
89 if (p->p_pid == filemon->pid)
98 filemon_comment(struct filemon *filemon)
103 /* Load timestamp before locking. Less accurate but less contention. */
106 /* Grab a read lock on the filemon inuse list. */
109 /* Lock the found filemon structure. */
110 filemon_filemon_lock(filemon);
112 len = snprintf(filemon->msgbufr, sizeof(filemon->msgbufr),
113 "# filemon version %d\n# Target pid %d\n# Start %ju.%06ju\nV %d\n",
114 FILEMON_VERSION, curproc->p_pid, (uintmax_t)now.tv_sec,
115 (uintmax_t)now.tv_usec, FILEMON_VERSION);
117 filemon_output(filemon, filemon->msgbufr, len);
119 /* Unlock the found filemon structure. */
120 filemon_filemon_unlock(filemon);
122 /* Release the read lock. */
123 filemon_unlock_read();
127 filemon_wrapper_chdir(struct thread *td, struct chdir_args *uap)
132 struct filemon *filemon;
134 if ((ret = sys_chdir(td, uap)) == 0) {
135 /* Grab a read lock on the filemon inuse list. */
138 if ((filemon = filemon_pid_check(curproc)) != NULL) {
139 /* Lock the found filemon structure. */
140 filemon_filemon_lock(filemon);
142 copyinstr(uap->path, filemon->fname1,
143 sizeof(filemon->fname1), &done);
145 len = snprintf(filemon->msgbufr,
146 sizeof(filemon->msgbufr), "C %d %s\n",
147 curproc->p_pid, filemon->fname1);
149 filemon_output(filemon, filemon->msgbufr, len);
151 /* Unlock the found filemon structure. */
152 filemon_filemon_unlock(filemon);
155 /* Release the read lock. */
156 filemon_unlock_read();
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 /* Grab a read lock on the filemon inuse list. */
177 if ((filemon = filemon_pid_check(curproc)) != NULL) {
178 /* Lock the found filemon structure. */
179 filemon_filemon_lock(filemon);
181 len = snprintf(filemon->msgbufr,
182 sizeof(filemon->msgbufr), "E %d %s\n",
183 curproc->p_pid, fname);
185 filemon_output(filemon, filemon->msgbufr, len);
187 /* Unlock the found filemon structure. */
188 filemon_filemon_unlock(filemon);
191 /* Release the read lock. */
192 filemon_unlock_read();
198 #if defined(COMPAT_IA32) || defined(COMPAT_FREEBSD32) || defined(COMPAT_ARCH32)
200 filemon_wrapper_freebsd32_execve(struct thread *td,
201 struct freebsd32_execve_args *uap)
203 char fname[MAXPATHLEN];
207 struct filemon *filemon;
209 copyinstr(uap->fname, fname, sizeof(fname), &done);
211 if ((ret = freebsd32_execve(td, uap)) == 0) {
212 /* Grab a read lock on the filemon inuse list. */
215 if ((filemon = filemon_pid_check(curproc)) != NULL) {
216 /* Lock the found filemon structure. */
217 filemon_filemon_lock(filemon);
219 len = snprintf(filemon->msgbufr,
220 sizeof(filemon->msgbufr), "E %d %s\n",
221 curproc->p_pid, fname);
223 filemon_output(filemon, filemon->msgbufr, len);
225 /* Unlock the found filemon structure. */
226 filemon_filemon_unlock(filemon);
229 /* Release the read lock. */
230 filemon_unlock_read();
238 filemon_wrapper_fork(struct thread *td, struct fork_args *uap)
242 struct filemon *filemon;
244 if ((ret = sys_fork(td, uap)) == 0) {
245 /* Grab a read lock on the filemon inuse list. */
248 if ((filemon = filemon_pid_check(curproc)) != NULL) {
249 /* Lock the found filemon structure. */
250 filemon_filemon_lock(filemon);
252 len = snprintf(filemon->msgbufr,
253 sizeof(filemon->msgbufr), "F %d %ld\n",
254 curproc->p_pid, (long)curthread->td_retval[0]);
256 filemon_output(filemon, filemon->msgbufr, len);
258 /* Unlock the found filemon structure. */
259 filemon_filemon_unlock(filemon);
262 /* Release the read lock. */
263 filemon_unlock_read();
270 filemon_wrapper_open(struct thread *td, struct open_args *uap)
275 struct filemon *filemon;
277 if ((ret = sys_open(td, uap)) == 0) {
278 /* Grab a read lock on the filemon inuse list. */
281 if ((filemon = filemon_pid_check(curproc)) != NULL) {
282 /* Lock the found filemon structure. */
283 filemon_filemon_lock(filemon);
285 copyinstr(uap->path, filemon->fname1,
286 sizeof(filemon->fname1), &done);
288 if (uap->flags & O_RDWR) {
290 * We'll get the W record below, but need
291 * to also output an R to distingish from
294 len = snprintf(filemon->msgbufr,
295 sizeof(filemon->msgbufr), "R %d %s\n",
296 curproc->p_pid, filemon->fname1);
297 filemon_output(filemon, filemon->msgbufr, len);
301 len = snprintf(filemon->msgbufr,
302 sizeof(filemon->msgbufr), "%c %d %s\n",
303 (uap->flags & O_ACCMODE) ? 'W':'R',
304 curproc->p_pid, filemon->fname1);
305 filemon_output(filemon, filemon->msgbufr, len);
307 /* Unlock the found filemon structure. */
308 filemon_filemon_unlock(filemon);
311 /* Release the read lock. */
312 filemon_unlock_read();
319 filemon_wrapper_rename(struct thread *td, struct rename_args *uap)
324 struct filemon *filemon;
326 if ((ret = sys_rename(td, uap)) == 0) {
327 /* Grab a read lock on the filemon inuse list. */
330 if ((filemon = filemon_pid_check(curproc)) != NULL) {
331 /* Lock the found filemon structure. */
332 filemon_filemon_lock(filemon);
334 copyinstr(uap->from, filemon->fname1,
335 sizeof(filemon->fname1), &done);
336 copyinstr(uap->to, filemon->fname2,
337 sizeof(filemon->fname2), &done);
339 len = snprintf(filemon->msgbufr,
340 sizeof(filemon->msgbufr), "M %d '%s' '%s'\n",
341 curproc->p_pid, filemon->fname1, filemon->fname2);
343 filemon_output(filemon, filemon->msgbufr, len);
345 /* Unlock the found filemon structure. */
346 filemon_filemon_unlock(filemon);
349 /* Release the read lock. */
350 filemon_unlock_read();
357 filemon_wrapper_link(struct thread *td, struct link_args *uap)
362 struct filemon *filemon;
364 if ((ret = sys_link(td, uap)) == 0) {
365 /* Grab a read lock on the filemon inuse list. */
368 if ((filemon = filemon_pid_check(curproc)) != NULL) {
369 /* Lock the found filemon structure. */
370 filemon_filemon_lock(filemon);
372 copyinstr(uap->path, filemon->fname1,
373 sizeof(filemon->fname1), &done);
374 copyinstr(uap->link, filemon->fname2,
375 sizeof(filemon->fname2), &done);
377 len = snprintf(filemon->msgbufr,
378 sizeof(filemon->msgbufr), "L %d '%s' '%s'\n",
379 curproc->p_pid, filemon->fname1, filemon->fname2);
381 filemon_output(filemon, filemon->msgbufr, len);
383 /* Unlock the found filemon structure. */
384 filemon_filemon_unlock(filemon);
387 /* Release the read lock. */
388 filemon_unlock_read();
395 filemon_wrapper_symlink(struct thread *td, struct symlink_args *uap)
400 struct filemon *filemon;
402 if ((ret = sys_symlink(td, uap)) == 0) {
403 /* Grab a read lock on the filemon inuse list. */
406 if ((filemon = filemon_pid_check(curproc)) != NULL) {
407 /* Lock the found filemon structure. */
408 filemon_filemon_lock(filemon);
410 copyinstr(uap->path, filemon->fname1,
411 sizeof(filemon->fname1), &done);
412 copyinstr(uap->link, filemon->fname2,
413 sizeof(filemon->fname2), &done);
415 len = snprintf(filemon->msgbufr,
416 sizeof(filemon->msgbufr), "L %d '%s' '%s'\n",
417 curproc->p_pid, filemon->fname1, filemon->fname2);
419 filemon_output(filemon, filemon->msgbufr, len);
421 /* Unlock the found filemon structure. */
422 filemon_filemon_unlock(filemon);
425 /* Release the read lock. */
426 filemon_unlock_read();
432 #ifdef FILEMON_HAS_LINKAT
434 filemon_wrapper_linkat(struct thread *td, struct linkat_args *uap)
439 struct filemon *filemon;
441 if ((ret = sys_linkat(td, uap)) == 0) {
442 /* Grab a read lock on the filemon inuse list. */
445 if ((filemon = filemon_pid_check(curproc)) != NULL) {
446 /* Lock the found filemon structure. */
447 filemon_filemon_lock(filemon);
449 copyinstr(uap->path1, filemon->fname1,
450 sizeof(filemon->fname1), &done);
451 copyinstr(uap->path2, filemon->fname2,
452 sizeof(filemon->fname2), &done);
454 len = snprintf(filemon->msgbufr,
455 sizeof(filemon->msgbufr), "L %d '%s' '%s'\n",
456 curproc->p_pid, filemon->fname1, filemon->fname2);
458 filemon_output(filemon, filemon->msgbufr, len);
460 /* Unlock the found filemon structure. */
461 filemon_filemon_unlock(filemon);
464 /* Release the read lock. */
465 filemon_unlock_read();
473 filemon_wrapper_stat(struct thread *td, struct stat_args *uap)
478 struct filemon *filemon;
480 if ((ret = sys_stat(td, uap)) == 0) {
481 /* Grab a read lock on the filemon inuse list. */
484 if ((filemon = filemon_pid_check(curproc)) != NULL) {
485 /* Lock the found filemon structure. */
486 filemon_filemon_lock(filemon);
488 copyinstr(uap->path, filemon->fname1,
489 sizeof(filemon->fname1), &done);
491 len = snprintf(filemon->msgbufr,
492 sizeof(filemon->msgbufr), "S %d %s\n",
493 curproc->p_pid, filemon->fname1);
495 filemon_output(filemon, filemon->msgbufr, len);
497 /* Unlock the found filemon structure. */
498 filemon_filemon_unlock(filemon);
501 /* Release the read lock. */
502 filemon_unlock_read();
508 #if defined(COMPAT_IA32) || defined(COMPAT_FREEBSD32) || defined(COMPAT_ARCH32)
510 filemon_wrapper_freebsd32_stat(struct thread *td,
511 struct freebsd32_stat_args *uap)
516 struct filemon *filemon;
518 if ((ret = freebsd32_stat(td, uap)) == 0) {
519 /* Grab a read lock on the filemon inuse list. */
522 if ((filemon = filemon_pid_check(curproc)) != NULL) {
523 /* Lock the found filemon structure. */
524 filemon_filemon_lock(filemon);
526 copyinstr(uap->path, filemon->fname1,
527 sizeof(filemon->fname1), &done);
529 len = snprintf(filemon->msgbufr,
530 sizeof(filemon->msgbufr), "S %d %s\n",
531 curproc->p_pid, filemon->fname1);
533 filemon_output(filemon, filemon->msgbufr, len);
535 /* Unlock the found filemon structure. */
536 filemon_filemon_unlock(filemon);
539 /* Release the read lock. */
540 filemon_unlock_read();
548 filemon_wrapper_sys_exit(struct thread *td, struct sys_exit_args *uap)
551 struct filemon *filemon;
554 /* Get timestamp before locking. */
557 /* Grab a read lock on the filemon inuse list. */
560 if ((filemon = filemon_pid_check(curproc)) != NULL) {
561 /* Lock the found filemon structure. */
562 filemon_filemon_lock(filemon);
564 len = snprintf(filemon->msgbufr, sizeof(filemon->msgbufr),
565 "X %d %d\n", curproc->p_pid, uap->rval);
567 filemon_output(filemon, filemon->msgbufr, len);
569 /* Check if the monitored process is about to exit. */
570 if (filemon->pid == curproc->p_pid) {
571 len = snprintf(filemon->msgbufr,
572 sizeof(filemon->msgbufr),
573 "# Stop %ju.%06ju\n# Bye bye\n",
574 (uintmax_t)now.tv_sec, (uintmax_t)now.tv_usec);
576 filemon_output(filemon, filemon->msgbufr, len);
580 /* Unlock the found filemon structure. */
581 filemon_filemon_unlock(filemon);
584 /* Release the read lock. */
585 filemon_unlock_read();
587 sys_sys_exit(td, uap);
591 filemon_wrapper_unlink(struct thread *td, struct unlink_args *uap)
596 struct filemon *filemon;
598 if ((ret = sys_unlink(td, uap)) == 0) {
599 /* Grab a read lock on the filemon inuse list. */
602 if ((filemon = filemon_pid_check(curproc)) != NULL) {
603 /* Lock the found filemon structure. */
604 filemon_filemon_lock(filemon);
606 copyinstr(uap->path, filemon->fname1,
607 sizeof(filemon->fname1), &done);
609 len = snprintf(filemon->msgbufr,
610 sizeof(filemon->msgbufr), "D %d %s\n",
611 curproc->p_pid, filemon->fname1);
613 filemon_output(filemon, filemon->msgbufr, len);
615 /* Unlock the found filemon structure. */
616 filemon_filemon_unlock(filemon);
619 /* Release the read lock. */
620 filemon_unlock_read();
627 filemon_wrapper_vfork(struct thread *td, struct vfork_args *uap)
631 struct filemon *filemon;
633 if ((ret = sys_vfork(td, uap)) == 0) {
634 /* Grab a read lock on the filemon inuse list. */
637 if ((filemon = filemon_pid_check(curproc)) != NULL) {
638 /* Lock the found filemon structure. */
639 filemon_filemon_lock(filemon);
641 len = snprintf(filemon->msgbufr,
642 sizeof(filemon->msgbufr), "F %d %ld\n",
643 curproc->p_pid, (long)curthread->td_retval[0]);
645 filemon_output(filemon, filemon->msgbufr, len);
647 /* Unlock the found filemon structure. */
648 filemon_filemon_unlock(filemon);
651 /* Release the read lock. */
652 filemon_unlock_read();
659 filemon_wrapper_install(void)
661 #if defined(__i386__)
662 struct sysent *sv_table = elf32_freebsd_sysvec.sv_table;
663 #elif defined(__amd64__)
664 struct sysent *sv_table = elf64_freebsd_sysvec.sv_table;
666 #error Machine type not supported
669 sv_table[SYS_chdir].sy_call = (sy_call_t *) filemon_wrapper_chdir;
670 sv_table[SYS_exit].sy_call = (sy_call_t *) filemon_wrapper_sys_exit;
671 sv_table[SYS_execve].sy_call = (sy_call_t *) filemon_wrapper_execve;
672 sv_table[SYS_fork].sy_call = (sy_call_t *) filemon_wrapper_fork;
673 sv_table[SYS_open].sy_call = (sy_call_t *) filemon_wrapper_open;
674 sv_table[SYS_rename].sy_call = (sy_call_t *) filemon_wrapper_rename;
675 sv_table[SYS_stat].sy_call = (sy_call_t *) filemon_wrapper_stat;
676 sv_table[SYS_unlink].sy_call = (sy_call_t *) filemon_wrapper_unlink;
677 sv_table[SYS_vfork].sy_call = (sy_call_t *) filemon_wrapper_vfork;
678 sv_table[SYS_link].sy_call = (sy_call_t *) filemon_wrapper_link;
679 sv_table[SYS_symlink].sy_call = (sy_call_t *) filemon_wrapper_symlink;
680 #ifdef FILEMON_HAS_LINKAT
681 sv_table[SYS_linkat].sy_call = (sy_call_t *) filemon_wrapper_linkat;
684 #if defined(COMPAT_IA32) || defined(COMPAT_FREEBSD32) || defined(COMPAT_ARCH32)
685 sv_table = ia32_freebsd_sysvec.sv_table;
687 sv_table[FREEBSD32_SYS_chdir].sy_call = (sy_call_t *) filemon_wrapper_chdir;
688 sv_table[FREEBSD32_SYS_exit].sy_call = (sy_call_t *) filemon_wrapper_sys_exit;
689 sv_table[FREEBSD32_SYS_freebsd32_execve].sy_call = (sy_call_t *) filemon_wrapper_freebsd32_execve;
690 sv_table[FREEBSD32_SYS_fork].sy_call = (sy_call_t *) filemon_wrapper_fork;
691 sv_table[FREEBSD32_SYS_open].sy_call = (sy_call_t *) filemon_wrapper_open;
692 sv_table[FREEBSD32_SYS_rename].sy_call = (sy_call_t *) filemon_wrapper_rename;
693 sv_table[FREEBSD32_SYS_freebsd32_stat].sy_call = (sy_call_t *) filemon_wrapper_freebsd32_stat;
694 sv_table[FREEBSD32_SYS_unlink].sy_call = (sy_call_t *) filemon_wrapper_unlink;
695 sv_table[FREEBSD32_SYS_vfork].sy_call = (sy_call_t *) filemon_wrapper_vfork;
696 sv_table[FREEBSD32_SYS_link].sy_call = (sy_call_t *) filemon_wrapper_link;
697 sv_table[FREEBSD32_SYS_symlink].sy_call = (sy_call_t *) filemon_wrapper_symlink;
698 #ifdef FILEMON_HAS_LINKAT
699 sv_table[FREEBSD32_SYS_linkat].sy_call = (sy_call_t *) filemon_wrapper_linkat;
701 #endif /* COMPAT_ARCH32 */
705 filemon_wrapper_deinstall(void)
707 #if defined(__i386__)
708 struct sysent *sv_table = elf32_freebsd_sysvec.sv_table;
709 #elif defined(__amd64__)
710 struct sysent *sv_table = elf64_freebsd_sysvec.sv_table;
712 #error Machine type not supported
715 sv_table[SYS_chdir].sy_call = (sy_call_t *)sys_chdir;
716 sv_table[SYS_exit].sy_call = (sy_call_t *)sys_sys_exit;
717 sv_table[SYS_execve].sy_call = (sy_call_t *)sys_execve;
718 sv_table[SYS_fork].sy_call = (sy_call_t *)sys_fork;
719 sv_table[SYS_open].sy_call = (sy_call_t *)sys_open;
720 sv_table[SYS_rename].sy_call = (sy_call_t *)sys_rename;
721 sv_table[SYS_stat].sy_call = (sy_call_t *)sys_stat;
722 sv_table[SYS_unlink].sy_call = (sy_call_t *)sys_unlink;
723 sv_table[SYS_vfork].sy_call = (sy_call_t *)sys_vfork;
724 sv_table[SYS_link].sy_call = (sy_call_t *)sys_link;
725 sv_table[SYS_symlink].sy_call = (sy_call_t *)sys_symlink;
726 #ifdef FILEMON_HAS_LINKAT
727 sv_table[SYS_linkat].sy_call = (sy_call_t *)sys_linkat;
730 #if defined(COMPAT_IA32) || defined(COMPAT_FREEBSD32) || defined(COMPAT_ARCH32)
731 sv_table = ia32_freebsd_sysvec.sv_table;
733 sv_table[FREEBSD32_SYS_chdir].sy_call = (sy_call_t *)sys_chdir;
734 sv_table[FREEBSD32_SYS_exit].sy_call = (sy_call_t *)sys_sys_exit;
735 sv_table[FREEBSD32_SYS_freebsd32_execve].sy_call = (sy_call_t *)freebsd32_execve;
736 sv_table[FREEBSD32_SYS_fork].sy_call = (sy_call_t *)sys_fork;
737 sv_table[FREEBSD32_SYS_open].sy_call = (sy_call_t *)sys_open;
738 sv_table[FREEBSD32_SYS_rename].sy_call = (sy_call_t *)sys_rename;
739 sv_table[FREEBSD32_SYS_freebsd32_stat].sy_call = (sy_call_t *)freebsd32_stat;
740 sv_table[FREEBSD32_SYS_unlink].sy_call = (sy_call_t *)sys_unlink;
741 sv_table[FREEBSD32_SYS_vfork].sy_call = (sy_call_t *)sys_vfork;
742 sv_table[FREEBSD32_SYS_link].sy_call = (sy_call_t *)sys_link;
743 sv_table[FREEBSD32_SYS_symlink].sy_call = (sy_call_t *)sys_symlink;
744 #ifdef FILEMON_HAS_LINKAT
745 sv_table[FREEBSD32_SYS_linkat].sy_call = (sy_call_t *)sys_linkat;
747 #endif /* COMPAT_ARCH32 */