2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 * Copyright (c) 2011, David E. O'Brien.
5 * Copyright (c) 2009-2011, Juniper Networks, Inc.
6 * Copyright (c) 2015-2016, EMC Corp.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
18 * THIS SOFTWARE IS PROVIDED BY JUNIPER NETWORKS AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL JUNIPER NETWORKS OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
34 #include <sys/eventhandler.h>
35 #include <sys/filedesc.h>
36 #include <sys/imgact.h>
39 #include <sys/sysent.h>
40 #include <sys/vnode.h>
42 static eventhandler_tag filemon_exec_tag;
43 static eventhandler_tag filemon_exit_tag;
44 static eventhandler_tag filemon_fork_tag;
47 filemon_output(struct filemon *filemon, char *msg, size_t len)
53 if (filemon->fp == NULL)
61 auio.uio_segflg = UIO_SYSSPACE;
62 auio.uio_rw = UIO_WRITE;
63 auio.uio_td = curthread;
64 auio.uio_offset = (off_t) -1;
66 if (filemon->fp->f_type == DTYPE_VNODE)
69 error = fo_write(filemon->fp, &auio, filemon->cred, 0, curthread);
70 if (error != 0 && filemon->error == 0)
71 filemon->error = error;
75 filemon_wrapper_chdir(struct thread *td, struct chdir_args *uap)
79 struct filemon *filemon;
81 if ((ret = sys_chdir(td, uap)) == 0) {
82 if ((filemon = filemon_proc_get(curproc)) != NULL) {
83 if ((error = copyinstr(uap->path, filemon->fname1,
84 sizeof(filemon->fname1), NULL)) != 0) {
85 filemon->error = error;
89 len = snprintf(filemon->msgbufr,
90 sizeof(filemon->msgbufr), "C %d %s\n",
91 curproc->p_pid, filemon->fname1);
93 filemon_output(filemon, filemon->msgbufr, len);
95 filemon_drop(filemon);
103 filemon_event_process_exec(void *arg __unused, struct proc *p,
104 struct image_params *imgp)
106 struct filemon *filemon;
109 if ((filemon = filemon_proc_get(p)) != NULL) {
110 len = snprintf(filemon->msgbufr,
111 sizeof(filemon->msgbufr), "E %d %s\n",
113 imgp->execpath != NULL ? imgp->execpath : "<unknown>");
115 filemon_output(filemon, filemon->msgbufr, len);
117 /* If the credentials changed then cease tracing. */
118 if (imgp->newcred != NULL &&
119 imgp->credential_setid &&
120 priv_check_cred(filemon->cred,
121 PRIV_DEBUG_DIFFCRED, 0) != 0) {
123 * It may have changed to NULL already, but
124 * will not be re-attached by anything else.
126 if (p->p_filemon != NULL) {
127 KASSERT(p->p_filemon == filemon,
128 ("%s: proc %p didn't have expected"
129 " filemon %p", __func__, p, filemon));
130 filemon_proc_drop(p);
135 filemon_drop(filemon);
140 _filemon_wrapper_openat(struct thread *td, char *upath, int flags, int fd)
145 struct filemon *filemon;
146 char *atpath, *freepath;
149 if ((filemon = filemon_proc_get(curproc)) != NULL) {
154 if ((error = copyinstr(upath, filemon->fname1,
155 sizeof(filemon->fname1), NULL)) != 0) {
156 filemon->error = error;
160 if (filemon->fname1[0] != '/' && fd != AT_FDCWD) {
162 * rats - we cannot do too much about this.
163 * the trace should show a dir we read
164 * recently.. output an A record as a clue
165 * until we can do better.
166 * XXX: This may be able to come out with
167 * the namecache lookup now.
169 len = snprintf(filemon->msgbufr,
170 sizeof(filemon->msgbufr), "A %d %s\n",
171 curproc->p_pid, filemon->fname1);
172 filemon_output(filemon, filemon->msgbufr, len);
174 * Try to resolve the path from the vnode using the
175 * namecache. It may be inaccurate, but better
179 cap_rights_init(&rights, CAP_LOOKUP), &fp) == 0) {
180 vn_fullpath(td, fp->f_vnode, &atpath,
184 if (flags & O_RDWR) {
186 * We'll get the W record below, but need
187 * to also output an R to distinguish from
190 len = snprintf(filemon->msgbufr,
191 sizeof(filemon->msgbufr), "R %d %s%s%s\n",
192 curproc->p_pid, atpath,
193 atpath[0] != '\0' ? "/" : "", filemon->fname1);
194 filemon_output(filemon, filemon->msgbufr, len);
197 len = snprintf(filemon->msgbufr,
198 sizeof(filemon->msgbufr), "%c %d %s%s%s\n",
199 (flags & O_ACCMODE) ? 'W':'R',
200 curproc->p_pid, atpath,
201 atpath[0] != '\0' ? "/" : "", filemon->fname1);
202 filemon_output(filemon, filemon->msgbufr, len);
204 filemon_drop(filemon);
207 free(freepath, M_TEMP);
212 filemon_wrapper_open(struct thread *td, struct open_args *uap)
216 if ((ret = sys_open(td, uap)) == 0)
217 _filemon_wrapper_openat(td, uap->path, uap->flags, AT_FDCWD);
223 filemon_wrapper_openat(struct thread *td, struct openat_args *uap)
227 if ((ret = sys_openat(td, uap)) == 0)
228 _filemon_wrapper_openat(td, uap->path, uap->flag, uap->fd);
234 filemon_wrapper_rename(struct thread *td, struct rename_args *uap)
238 struct filemon *filemon;
240 if ((ret = sys_rename(td, uap)) == 0) {
241 if ((filemon = filemon_proc_get(curproc)) != NULL) {
242 if (((error = copyinstr(uap->from, filemon->fname1,
243 sizeof(filemon->fname1), NULL)) != 0) ||
244 ((error = copyinstr(uap->to, filemon->fname2,
245 sizeof(filemon->fname2), NULL)) != 0)) {
246 filemon->error = error;
250 len = snprintf(filemon->msgbufr,
251 sizeof(filemon->msgbufr), "M %d '%s' '%s'\n",
252 curproc->p_pid, filemon->fname1, filemon->fname2);
254 filemon_output(filemon, filemon->msgbufr, len);
256 filemon_drop(filemon);
264 _filemon_wrapper_link(struct thread *td, char *upath1, char *upath2)
266 struct filemon *filemon;
270 if ((filemon = filemon_proc_get(curproc)) != NULL) {
271 if (((error = copyinstr(upath1, filemon->fname1,
272 sizeof(filemon->fname1), NULL)) != 0) ||
273 ((error = copyinstr(upath2, filemon->fname2,
274 sizeof(filemon->fname2), NULL)) != 0)) {
275 filemon->error = error;
279 len = snprintf(filemon->msgbufr,
280 sizeof(filemon->msgbufr), "L %d '%s' '%s'\n",
281 curproc->p_pid, filemon->fname1, filemon->fname2);
283 filemon_output(filemon, filemon->msgbufr, len);
285 filemon_drop(filemon);
290 filemon_wrapper_link(struct thread *td, struct link_args *uap)
294 if ((ret = sys_link(td, uap)) == 0)
295 _filemon_wrapper_link(td, uap->path, uap->link);
301 filemon_wrapper_symlink(struct thread *td, struct symlink_args *uap)
305 if ((ret = sys_symlink(td, uap)) == 0)
306 _filemon_wrapper_link(td, uap->path, uap->link);
312 filemon_wrapper_linkat(struct thread *td, struct linkat_args *uap)
316 if ((ret = sys_linkat(td, uap)) == 0)
317 _filemon_wrapper_link(td, uap->path1, uap->path2);
323 filemon_event_process_exit(void *arg __unused, struct proc *p)
326 struct filemon *filemon;
328 if ((filemon = filemon_proc_get(p)) != NULL) {
329 len = snprintf(filemon->msgbufr, sizeof(filemon->msgbufr),
330 "X %d %d %d\n", p->p_pid, p->p_xexit, p->p_xsig);
332 filemon_output(filemon, filemon->msgbufr, len);
335 * filemon_untrack_processes() may have dropped this p_filemon
336 * already while in filemon_proc_get() before acquiring the
339 KASSERT(p->p_filemon == NULL || p->p_filemon == filemon,
340 ("%s: p %p was attached while exiting, expected "
341 "filemon %p or NULL", __func__, p, filemon));
342 if (p->p_filemon == filemon)
343 filemon_proc_drop(p);
345 filemon_drop(filemon);
350 filemon_wrapper_unlink(struct thread *td, struct unlink_args *uap)
354 struct filemon *filemon;
356 if ((ret = sys_unlink(td, uap)) == 0) {
357 if ((filemon = filemon_proc_get(curproc)) != NULL) {
358 if ((error = copyinstr(uap->path, filemon->fname1,
359 sizeof(filemon->fname1), NULL)) != 0) {
360 filemon->error = error;
364 len = snprintf(filemon->msgbufr,
365 sizeof(filemon->msgbufr), "D %d %s\n",
366 curproc->p_pid, filemon->fname1);
368 filemon_output(filemon, filemon->msgbufr, len);
370 filemon_drop(filemon);
378 filemon_event_process_fork(void *arg __unused, struct proc *p1,
379 struct proc *p2, int flags __unused)
382 struct filemon *filemon;
384 if ((filemon = filemon_proc_get(p1)) != NULL) {
385 len = snprintf(filemon->msgbufr,
386 sizeof(filemon->msgbufr), "F %d %d\n",
387 p1->p_pid, p2->p_pid);
389 filemon_output(filemon, filemon->msgbufr, len);
392 * filemon_untrack_processes() or
393 * filemon_ioctl(FILEMON_SET_PID) may have changed the parent's
394 * p_filemon while in filemon_proc_get() before acquiring the
395 * filemon lock. Only inherit if the parent is still traced by
398 if (p1->p_filemon == filemon) {
401 * It may have been attached to already by a new
404 if (p2->p_filemon == NULL) {
405 p2->p_filemon = filemon_acquire(filemon);
411 filemon_drop(filemon);
416 filemon_wrapper_install(void)
419 sysent[SYS_chdir].sy_call = (sy_call_t *) filemon_wrapper_chdir;
420 sysent[SYS_open].sy_call = (sy_call_t *) filemon_wrapper_open;
421 sysent[SYS_openat].sy_call = (sy_call_t *) filemon_wrapper_openat;
422 sysent[SYS_rename].sy_call = (sy_call_t *) filemon_wrapper_rename;
423 sysent[SYS_unlink].sy_call = (sy_call_t *) filemon_wrapper_unlink;
424 sysent[SYS_link].sy_call = (sy_call_t *) filemon_wrapper_link;
425 sysent[SYS_symlink].sy_call = (sy_call_t *) filemon_wrapper_symlink;
426 sysent[SYS_linkat].sy_call = (sy_call_t *) filemon_wrapper_linkat;
428 #if defined(COMPAT_FREEBSD32)
429 freebsd32_sysent[FREEBSD32_SYS_chdir].sy_call = (sy_call_t *) filemon_wrapper_chdir;
430 freebsd32_sysent[FREEBSD32_SYS_open].sy_call = (sy_call_t *) filemon_wrapper_open;
431 freebsd32_sysent[FREEBSD32_SYS_openat].sy_call = (sy_call_t *) filemon_wrapper_openat;
432 freebsd32_sysent[FREEBSD32_SYS_rename].sy_call = (sy_call_t *) filemon_wrapper_rename;
433 freebsd32_sysent[FREEBSD32_SYS_unlink].sy_call = (sy_call_t *) filemon_wrapper_unlink;
434 freebsd32_sysent[FREEBSD32_SYS_link].sy_call = (sy_call_t *) filemon_wrapper_link;
435 freebsd32_sysent[FREEBSD32_SYS_symlink].sy_call = (sy_call_t *) filemon_wrapper_symlink;
436 freebsd32_sysent[FREEBSD32_SYS_linkat].sy_call = (sy_call_t *) filemon_wrapper_linkat;
437 #endif /* COMPAT_FREEBSD32 */
439 filemon_exec_tag = EVENTHANDLER_REGISTER(process_exec,
440 filemon_event_process_exec, NULL, EVENTHANDLER_PRI_LAST);
441 filemon_exit_tag = EVENTHANDLER_REGISTER(process_exit,
442 filemon_event_process_exit, NULL, EVENTHANDLER_PRI_LAST);
443 filemon_fork_tag = EVENTHANDLER_REGISTER(process_fork,
444 filemon_event_process_fork, NULL, EVENTHANDLER_PRI_LAST);
448 filemon_wrapper_deinstall(void)
451 sysent[SYS_chdir].sy_call = (sy_call_t *)sys_chdir;
452 sysent[SYS_open].sy_call = (sy_call_t *)sys_open;
453 sysent[SYS_openat].sy_call = (sy_call_t *)sys_openat;
454 sysent[SYS_rename].sy_call = (sy_call_t *)sys_rename;
455 sysent[SYS_unlink].sy_call = (sy_call_t *)sys_unlink;
456 sysent[SYS_link].sy_call = (sy_call_t *)sys_link;
457 sysent[SYS_symlink].sy_call = (sy_call_t *)sys_symlink;
458 sysent[SYS_linkat].sy_call = (sy_call_t *)sys_linkat;
460 #if defined(COMPAT_FREEBSD32)
461 freebsd32_sysent[FREEBSD32_SYS_chdir].sy_call = (sy_call_t *)sys_chdir;
462 freebsd32_sysent[FREEBSD32_SYS_open].sy_call = (sy_call_t *)sys_open;
463 freebsd32_sysent[FREEBSD32_SYS_openat].sy_call = (sy_call_t *)sys_openat;
464 freebsd32_sysent[FREEBSD32_SYS_rename].sy_call = (sy_call_t *)sys_rename;
465 freebsd32_sysent[FREEBSD32_SYS_unlink].sy_call = (sy_call_t *)sys_unlink;
466 freebsd32_sysent[FREEBSD32_SYS_link].sy_call = (sy_call_t *)sys_link;
467 freebsd32_sysent[FREEBSD32_SYS_symlink].sy_call = (sy_call_t *)sys_symlink;
468 freebsd32_sysent[FREEBSD32_SYS_linkat].sy_call = (sy_call_t *)sys_linkat;
469 #endif /* COMPAT_FREEBSD32 */
471 EVENTHANDLER_DEREGISTER(process_exec, filemon_exec_tag);
472 EVENTHANDLER_DEREGISTER(process_exit, filemon_exit_tag);
473 EVENTHANDLER_DEREGISTER(process_fork, filemon_fork_tag);