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 #if __FreeBSD_version > 800032
40 #define FILEMON_HAS_LINKAT
43 #if __FreeBSD_version < 900044 /* r225617 (2011-09-16) failed to bump
44 __FreeBSD_version. This really should
45 be based on "900045". "900044" is r225469
46 (2011-09-10) so this code is broken for
47 9-CURRENT September 10th-16th. */
48 #define sys_chdir chdir
51 #define sys_rename rename
53 #define sys_symlink symlink
54 #define sys_unlink unlink
55 #ifdef FILEMON_HAS_LINKAT
56 #define sys_linkat linkat
58 #endif /* __FreeBSD_version */
60 static eventhandler_tag filemon_exec_tag;
61 static eventhandler_tag filemon_exit_tag;
62 static eventhandler_tag filemon_fork_tag;
65 filemon_output(struct filemon *filemon, char *msg, size_t len)
70 if (filemon->fp == NULL)
78 auio.uio_segflg = UIO_SYSSPACE;
79 auio.uio_rw = UIO_WRITE;
80 auio.uio_td = curthread;
81 auio.uio_offset = (off_t) -1;
85 fo_write(filemon->fp, &auio, curthread->td_ucred, 0, curthread);
88 static struct filemon *
89 filemon_pid_check(struct proc *p)
91 struct filemon *filemon;
94 if (TAILQ_EMPTY(&filemons_inuse)) {
95 filemon_unlock_read();
98 sx_slock(&proctree_lock);
99 while (p->p_pid != 0) {
100 TAILQ_FOREACH(filemon, &filemons_inuse, link) {
101 if (p == filemon->p) {
102 sx_sunlock(&proctree_lock);
103 filemon_filemon_lock(filemon);
104 filemon_unlock_read();
108 p = proc_realparent(p);
110 sx_sunlock(&proctree_lock);
111 filemon_unlock_read();
116 filemon_wrapper_chdir(struct thread *td, struct chdir_args *uap)
121 struct filemon *filemon;
123 if ((ret = sys_chdir(td, uap)) == 0) {
124 if ((filemon = filemon_pid_check(curproc)) != NULL) {
125 copyinstr(uap->path, filemon->fname1,
126 sizeof(filemon->fname1), &done);
128 len = snprintf(filemon->msgbufr,
129 sizeof(filemon->msgbufr), "C %d %s\n",
130 curproc->p_pid, filemon->fname1);
132 filemon_output(filemon, filemon->msgbufr, len);
134 /* Unlock the found filemon structure. */
135 filemon_filemon_unlock(filemon);
143 filemon_event_process_exec(void *arg __unused, struct proc *p,
144 struct image_params *imgp)
146 struct filemon *filemon;
147 char *fullpath, *freepath;
150 if ((filemon = filemon_pid_check(p)) != NULL) {
151 fullpath = "<unknown>";
154 vn_fullpath(FIRST_THREAD_IN_PROC(p), imgp->vp, &fullpath,
157 len = snprintf(filemon->msgbufr,
158 sizeof(filemon->msgbufr), "E %d %s\n",
161 filemon_output(filemon, filemon->msgbufr, len);
163 /* Unlock the found filemon structure. */
164 filemon_filemon_unlock(filemon);
166 free(freepath, M_TEMP);
171 filemon_wrapper_open(struct thread *td, struct open_args *uap)
176 struct filemon *filemon;
178 if ((ret = sys_open(td, uap)) == 0) {
179 if ((filemon = filemon_pid_check(curproc)) != NULL) {
180 copyinstr(uap->path, filemon->fname1,
181 sizeof(filemon->fname1), &done);
183 if (uap->flags & O_RDWR) {
185 * We'll get the W record below, but need
186 * to also output an R to distingish from
189 len = snprintf(filemon->msgbufr,
190 sizeof(filemon->msgbufr), "R %d %s\n",
191 curproc->p_pid, filemon->fname1);
192 filemon_output(filemon, filemon->msgbufr, len);
196 len = snprintf(filemon->msgbufr,
197 sizeof(filemon->msgbufr), "%c %d %s\n",
198 (uap->flags & O_ACCMODE) ? 'W':'R',
199 curproc->p_pid, filemon->fname1);
200 filemon_output(filemon, filemon->msgbufr, len);
202 /* Unlock the found filemon structure. */
203 filemon_filemon_unlock(filemon);
211 filemon_wrapper_openat(struct thread *td, struct openat_args *uap)
216 struct filemon *filemon;
218 if ((ret = sys_openat(td, uap)) == 0) {
219 if ((filemon = filemon_pid_check(curproc)) != NULL) {
220 copyinstr(uap->path, filemon->fname1,
221 sizeof(filemon->fname1), &done);
223 filemon->fname2[0] = '\0';
224 if (filemon->fname1[0] != '/' && uap->fd != AT_FDCWD) {
226 * rats - we cannot do too much about this.
227 * the trace should show a dir we read
228 * recently.. output an A record as a clue
229 * until we can do better.
231 len = snprintf(filemon->msgbufr,
232 sizeof(filemon->msgbufr), "A %d %s\n",
233 curproc->p_pid, filemon->fname1);
234 filemon_output(filemon, filemon->msgbufr, len);
236 if (uap->flag & O_RDWR) {
238 * We'll get the W record below, but need
239 * to also output an R to distingish from
242 len = snprintf(filemon->msgbufr,
243 sizeof(filemon->msgbufr), "R %d %s%s\n",
244 curproc->p_pid, filemon->fname2, filemon->fname1);
245 filemon_output(filemon, filemon->msgbufr, len);
249 len = snprintf(filemon->msgbufr,
250 sizeof(filemon->msgbufr), "%c %d %s%s\n",
251 (uap->flag & O_ACCMODE) ? 'W':'R',
252 curproc->p_pid, filemon->fname2, filemon->fname1);
253 filemon_output(filemon, filemon->msgbufr, len);
255 /* Unlock the found filemon structure. */
256 filemon_filemon_unlock(filemon);
264 filemon_wrapper_rename(struct thread *td, struct rename_args *uap)
269 struct filemon *filemon;
271 if ((ret = sys_rename(td, uap)) == 0) {
272 if ((filemon = filemon_pid_check(curproc)) != NULL) {
273 copyinstr(uap->from, filemon->fname1,
274 sizeof(filemon->fname1), &done);
275 copyinstr(uap->to, filemon->fname2,
276 sizeof(filemon->fname2), &done);
278 len = snprintf(filemon->msgbufr,
279 sizeof(filemon->msgbufr), "M %d '%s' '%s'\n",
280 curproc->p_pid, filemon->fname1, filemon->fname2);
282 filemon_output(filemon, filemon->msgbufr, len);
284 /* Unlock the found filemon structure. */
285 filemon_filemon_unlock(filemon);
293 filemon_wrapper_link(struct thread *td, struct link_args *uap)
298 struct filemon *filemon;
300 if ((ret = sys_link(td, uap)) == 0) {
301 if ((filemon = filemon_pid_check(curproc)) != NULL) {
302 copyinstr(uap->path, filemon->fname1,
303 sizeof(filemon->fname1), &done);
304 copyinstr(uap->link, filemon->fname2,
305 sizeof(filemon->fname2), &done);
307 len = snprintf(filemon->msgbufr,
308 sizeof(filemon->msgbufr), "L %d '%s' '%s'\n",
309 curproc->p_pid, filemon->fname1, filemon->fname2);
311 filemon_output(filemon, filemon->msgbufr, len);
313 /* Unlock the found filemon structure. */
314 filemon_filemon_unlock(filemon);
322 filemon_wrapper_symlink(struct thread *td, struct symlink_args *uap)
327 struct filemon *filemon;
329 if ((ret = sys_symlink(td, uap)) == 0) {
330 if ((filemon = filemon_pid_check(curproc)) != NULL) {
331 copyinstr(uap->path, filemon->fname1,
332 sizeof(filemon->fname1), &done);
333 copyinstr(uap->link, filemon->fname2,
334 sizeof(filemon->fname2), &done);
336 len = snprintf(filemon->msgbufr,
337 sizeof(filemon->msgbufr), "L %d '%s' '%s'\n",
338 curproc->p_pid, filemon->fname1, filemon->fname2);
340 filemon_output(filemon, filemon->msgbufr, len);
342 /* Unlock the found filemon structure. */
343 filemon_filemon_unlock(filemon);
350 #ifdef FILEMON_HAS_LINKAT
352 filemon_wrapper_linkat(struct thread *td, struct linkat_args *uap)
357 struct filemon *filemon;
359 if ((ret = sys_linkat(td, uap)) == 0) {
360 if ((filemon = filemon_pid_check(curproc)) != NULL) {
361 copyinstr(uap->path1, filemon->fname1,
362 sizeof(filemon->fname1), &done);
363 copyinstr(uap->path2, filemon->fname2,
364 sizeof(filemon->fname2), &done);
366 len = snprintf(filemon->msgbufr,
367 sizeof(filemon->msgbufr), "L %d '%s' '%s'\n",
368 curproc->p_pid, filemon->fname1, filemon->fname2);
370 filemon_output(filemon, filemon->msgbufr, len);
372 /* Unlock the found filemon structure. */
373 filemon_filemon_unlock(filemon);
382 filemon_wrapper_stat(struct thread *td, struct stat_args *uap)
387 struct filemon *filemon;
389 if ((ret = sys_stat(td, uap)) == 0) {
390 if ((filemon = filemon_pid_check(curproc)) != NULL) {
391 copyinstr(uap->path, filemon->fname1,
392 sizeof(filemon->fname1), &done);
394 len = snprintf(filemon->msgbufr,
395 sizeof(filemon->msgbufr), "S %d %s\n",
396 curproc->p_pid, filemon->fname1);
398 filemon_output(filemon, filemon->msgbufr, len);
400 /* Unlock the found filemon structure. */
401 filemon_filemon_unlock(filemon);
408 #if defined(COMPAT_IA32) || defined(COMPAT_FREEBSD32) || defined(COMPAT_ARCH32)
410 filemon_wrapper_freebsd32_stat(struct thread *td,
411 struct freebsd32_stat_args *uap)
416 struct filemon *filemon;
418 if ((ret = freebsd32_stat(td, uap)) == 0) {
419 if ((filemon = filemon_pid_check(curproc)) != NULL) {
420 copyinstr(uap->path, filemon->fname1,
421 sizeof(filemon->fname1), &done);
423 len = snprintf(filemon->msgbufr,
424 sizeof(filemon->msgbufr), "S %d %s\n",
425 curproc->p_pid, filemon->fname1);
427 filemon_output(filemon, filemon->msgbufr, len);
429 /* Unlock the found filemon structure. */
430 filemon_filemon_unlock(filemon);
439 filemon_event_process_exit(void *arg __unused, struct proc *p)
442 struct filemon *filemon;
445 /* Get timestamp before locking. */
448 if ((filemon = filemon_pid_check(p)) != NULL) {
449 len = snprintf(filemon->msgbufr, sizeof(filemon->msgbufr),
450 "X %d %d\n", p->p_pid, W_EXITCODE(p->p_xstat, 0));
452 filemon_output(filemon, filemon->msgbufr, len);
454 /* Check if the monitored process is about to exit. */
455 if (filemon->p == p) {
456 len = snprintf(filemon->msgbufr,
457 sizeof(filemon->msgbufr),
458 "# Stop %ju.%06ju\n# Bye bye\n",
459 (uintmax_t)now.tv_sec, (uintmax_t)now.tv_usec);
461 filemon_output(filemon, filemon->msgbufr, len);
465 /* Unlock the found filemon structure. */
466 filemon_filemon_unlock(filemon);
471 filemon_wrapper_unlink(struct thread *td, struct unlink_args *uap)
476 struct filemon *filemon;
478 if ((ret = sys_unlink(td, uap)) == 0) {
479 if ((filemon = filemon_pid_check(curproc)) != NULL) {
480 copyinstr(uap->path, filemon->fname1,
481 sizeof(filemon->fname1), &done);
483 len = snprintf(filemon->msgbufr,
484 sizeof(filemon->msgbufr), "D %d %s\n",
485 curproc->p_pid, filemon->fname1);
487 filemon_output(filemon, filemon->msgbufr, len);
489 /* Unlock the found filemon structure. */
490 filemon_filemon_unlock(filemon);
498 filemon_event_process_fork(void *arg __unused, struct proc *p1,
499 struct proc *p2, int flags __unused)
502 struct filemon *filemon;
504 if ((filemon = filemon_pid_check(p1)) != NULL) {
505 len = snprintf(filemon->msgbufr,
506 sizeof(filemon->msgbufr), "F %d %d\n",
507 p1->p_pid, p2->p_pid);
509 filemon_output(filemon, filemon->msgbufr, len);
511 /* Unlock the found filemon structure. */
512 filemon_filemon_unlock(filemon);
517 filemon_wrapper_install(void)
519 #if defined(__LP64__)
520 struct sysent *sv_table = elf64_freebsd_sysvec.sv_table;
522 struct sysent *sv_table = elf32_freebsd_sysvec.sv_table;
525 sv_table[SYS_chdir].sy_call = (sy_call_t *) filemon_wrapper_chdir;
526 sv_table[SYS_open].sy_call = (sy_call_t *) filemon_wrapper_open;
527 sv_table[SYS_openat].sy_call = (sy_call_t *) filemon_wrapper_openat;
528 sv_table[SYS_rename].sy_call = (sy_call_t *) filemon_wrapper_rename;
529 sv_table[SYS_stat].sy_call = (sy_call_t *) filemon_wrapper_stat;
530 sv_table[SYS_unlink].sy_call = (sy_call_t *) filemon_wrapper_unlink;
531 sv_table[SYS_link].sy_call = (sy_call_t *) filemon_wrapper_link;
532 sv_table[SYS_symlink].sy_call = (sy_call_t *) filemon_wrapper_symlink;
533 #ifdef FILEMON_HAS_LINKAT
534 sv_table[SYS_linkat].sy_call = (sy_call_t *) filemon_wrapper_linkat;
537 #if defined(COMPAT_IA32) || defined(COMPAT_FREEBSD32) || defined(COMPAT_ARCH32)
538 sv_table = ia32_freebsd_sysvec.sv_table;
540 sv_table[FREEBSD32_SYS_chdir].sy_call = (sy_call_t *) filemon_wrapper_chdir;
541 sv_table[FREEBSD32_SYS_open].sy_call = (sy_call_t *) filemon_wrapper_open;
542 sv_table[FREEBSD32_SYS_openat].sy_call = (sy_call_t *) filemon_wrapper_openat;
543 sv_table[FREEBSD32_SYS_rename].sy_call = (sy_call_t *) filemon_wrapper_rename;
544 sv_table[FREEBSD32_SYS_freebsd32_stat].sy_call = (sy_call_t *) filemon_wrapper_freebsd32_stat;
545 sv_table[FREEBSD32_SYS_unlink].sy_call = (sy_call_t *) filemon_wrapper_unlink;
546 sv_table[FREEBSD32_SYS_link].sy_call = (sy_call_t *) filemon_wrapper_link;
547 sv_table[FREEBSD32_SYS_symlink].sy_call = (sy_call_t *) filemon_wrapper_symlink;
548 #ifdef FILEMON_HAS_LINKAT
549 sv_table[FREEBSD32_SYS_linkat].sy_call = (sy_call_t *) filemon_wrapper_linkat;
551 #endif /* COMPAT_ARCH32 */
553 filemon_exec_tag = EVENTHANDLER_REGISTER(process_exec,
554 filemon_event_process_exec, NULL, EVENTHANDLER_PRI_LAST);
555 filemon_exit_tag = EVENTHANDLER_REGISTER(process_exit,
556 filemon_event_process_exit, NULL, EVENTHANDLER_PRI_LAST);
557 filemon_fork_tag = EVENTHANDLER_REGISTER(process_fork,
558 filemon_event_process_fork, NULL, EVENTHANDLER_PRI_LAST);
562 filemon_wrapper_deinstall(void)
564 #if defined(__LP64__)
565 struct sysent *sv_table = elf64_freebsd_sysvec.sv_table;
567 struct sysent *sv_table = elf32_freebsd_sysvec.sv_table;
570 sv_table[SYS_chdir].sy_call = (sy_call_t *)sys_chdir;
571 sv_table[SYS_open].sy_call = (sy_call_t *)sys_open;
572 sv_table[SYS_openat].sy_call = (sy_call_t *)sys_openat;
573 sv_table[SYS_rename].sy_call = (sy_call_t *)sys_rename;
574 sv_table[SYS_stat].sy_call = (sy_call_t *)sys_stat;
575 sv_table[SYS_unlink].sy_call = (sy_call_t *)sys_unlink;
576 sv_table[SYS_link].sy_call = (sy_call_t *)sys_link;
577 sv_table[SYS_symlink].sy_call = (sy_call_t *)sys_symlink;
578 #ifdef FILEMON_HAS_LINKAT
579 sv_table[SYS_linkat].sy_call = (sy_call_t *)sys_linkat;
582 #if defined(COMPAT_IA32) || defined(COMPAT_FREEBSD32) || defined(COMPAT_ARCH32)
583 sv_table = ia32_freebsd_sysvec.sv_table;
585 sv_table[FREEBSD32_SYS_chdir].sy_call = (sy_call_t *)sys_chdir;
586 sv_table[FREEBSD32_SYS_open].sy_call = (sy_call_t *)sys_open;
587 sv_table[FREEBSD32_SYS_openat].sy_call = (sy_call_t *)sys_openat;
588 sv_table[FREEBSD32_SYS_rename].sy_call = (sy_call_t *)sys_rename;
589 sv_table[FREEBSD32_SYS_freebsd32_stat].sy_call = (sy_call_t *)freebsd32_stat;
590 sv_table[FREEBSD32_SYS_unlink].sy_call = (sy_call_t *)sys_unlink;
591 sv_table[FREEBSD32_SYS_link].sy_call = (sy_call_t *)sys_link;
592 sv_table[FREEBSD32_SYS_symlink].sy_call = (sy_call_t *)sys_symlink;
593 #ifdef FILEMON_HAS_LINKAT
594 sv_table[FREEBSD32_SYS_linkat].sy_call = (sy_call_t *)sys_linkat;
596 #endif /* COMPAT_ARCH32 */
598 EVENTHANDLER_DEREGISTER(process_exec, filemon_exec_tag);
599 EVENTHANDLER_DEREGISTER(process_exit, filemon_exit_tag);
600 EVENTHANDLER_DEREGISTER(process_fork, filemon_fork_tag);