1 /*- 2 * Copyright (c) 2011, David E. O'Brien. 3 * Copyright (c) 2009-2011, Juniper Networks, Inc. 4 * Copyright (c) 2015, EMC Corp. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 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. 15 * 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 26 * SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __FBSDID("$FreeBSD$"); 31 32 #include <sys/imgact.h> 33 #include <sys/eventhandler.h> 34 #include <sys/sx.h> 35 #include <sys/vnode.h> 36 37 #include "opt_compat.h" 38 39 static eventhandler_tag filemon_exec_tag; 40 static eventhandler_tag filemon_exit_tag; 41 static eventhandler_tag filemon_fork_tag; 42 43 static void 44 filemon_output(struct filemon *filemon, char *msg, size_t len) 45 { 46 struct uio auio; 47 struct iovec aiov; 48 49 if (filemon->fp == NULL) 50 return; 51 52 aiov.iov_base = msg; 53 aiov.iov_len = len; 54 auio.uio_iov = &aiov; 55 auio.uio_iovcnt = 1; 56 auio.uio_resid = len; 57 auio.uio_segflg = UIO_SYSSPACE; 58 auio.uio_rw = UIO_WRITE; 59 auio.uio_td = curthread; 60 auio.uio_offset = (off_t) -1; 61 62 bwillwrite(); 63 64 fo_write(filemon->fp, &auio, curthread->td_ucred, 0, curthread); 65 } 66 67 static struct filemon * 68 filemon_pid_check(struct proc *p) 69 { 70 struct filemon *filemon; 71 72 filemon_lock_read(); 73 if (TAILQ_EMPTY(&filemons_inuse)) { 74 filemon_unlock_read(); 75 return (NULL); 76 } 77 sx_slock(&proctree_lock); 78 while (p->p_pid != 0) { 79 TAILQ_FOREACH(filemon, &filemons_inuse, link) { 80 if (p == filemon->p) { 81 sx_sunlock(&proctree_lock); 82 sx_xlock(&filemon->lock); 83 filemon_unlock_read(); 84 return (filemon); 85 } 86 } 87 p = proc_realparent(p); 88 } 89 sx_sunlock(&proctree_lock); 90 filemon_unlock_read(); 91 return (NULL); 92 } 93 94 static int 95 filemon_wrapper_chdir(struct thread *td, struct chdir_args *uap) 96 { 97 int ret; 98 size_t done; 99 size_t len; 100 struct filemon *filemon; 101 102 if ((ret = sys_chdir(td, uap)) == 0) { 103 if ((filemon = filemon_pid_check(curproc)) != NULL) { 104 copyinstr(uap->path, filemon->fname1, 105 sizeof(filemon->fname1), &done); 106 107 len = snprintf(filemon->msgbufr, 108 sizeof(filemon->msgbufr), "C %d %s\n", 109 curproc->p_pid, filemon->fname1); 110 111 filemon_output(filemon, filemon->msgbufr, len); 112 113 sx_xunlock(&filemon->lock); 114 } 115 } 116 117 return (ret); 118 } 119 120 static void 121 filemon_event_process_exec(void *arg __unused, struct proc *p, 122 struct image_params *imgp) 123 { 124 struct filemon *filemon; 125 char *fullpath, *freepath; 126 size_t len; 127 128 if ((filemon = filemon_pid_check(p)) != NULL) { 129 fullpath = "<unknown>"; 130 freepath = NULL; 131 132 vn_fullpath(FIRST_THREAD_IN_PROC(p), imgp->vp, &fullpath, 133 &freepath); 134 135 len = snprintf(filemon->msgbufr, 136 sizeof(filemon->msgbufr), "E %d %s\n", 137 p->p_pid, fullpath); 138 139 filemon_output(filemon, filemon->msgbufr, len); 140 141 sx_xunlock(&filemon->lock); 142 143 free(freepath, M_TEMP); 144 } 145 } 146 147 static int 148 filemon_wrapper_open(struct thread *td, struct open_args *uap) 149 { 150 int ret; 151 size_t done; 152 size_t len; 153 struct filemon *filemon; 154 155 if ((ret = sys_open(td, uap)) == 0) { 156 if ((filemon = filemon_pid_check(curproc)) != NULL) { 157 copyinstr(uap->path, filemon->fname1, 158 sizeof(filemon->fname1), &done); 159 160 if (uap->flags & O_RDWR) { 161 /* 162 * We'll get the W record below, but need 163 * to also output an R to distingish from 164 * O_WRONLY. 165 */ 166 len = snprintf(filemon->msgbufr, 167 sizeof(filemon->msgbufr), "R %d %s\n", 168 curproc->p_pid, filemon->fname1); 169 filemon_output(filemon, filemon->msgbufr, len); 170 } 171 172 173 len = snprintf(filemon->msgbufr, 174 sizeof(filemon->msgbufr), "%c %d %s\n", 175 (uap->flags & O_ACCMODE) ? 'W':'R', 176 curproc->p_pid, filemon->fname1); 177 filemon_output(filemon, filemon->msgbufr, len); 178 179 sx_xunlock(&filemon->lock); 180 } 181 } 182 183 return (ret); 184 } 185 186 static int 187 filemon_wrapper_openat(struct thread *td, struct openat_args *uap) 188 { 189 int ret; 190 size_t done; 191 size_t len; 192 struct filemon *filemon; 193 194 if ((ret = sys_openat(td, uap)) == 0) { 195 if ((filemon = filemon_pid_check(curproc)) != NULL) { 196 copyinstr(uap->path, filemon->fname1, 197 sizeof(filemon->fname1), &done); 198 199 filemon->fname2[0] = '\0'; 200 if (filemon->fname1[0] != '/' && uap->fd != AT_FDCWD) { 201 /* 202 * rats - we cannot do too much about this. 203 * the trace should show a dir we read 204 * recently.. output an A record as a clue 205 * until we can do better. 206 */ 207 len = snprintf(filemon->msgbufr, 208 sizeof(filemon->msgbufr), "A %d %s\n", 209 curproc->p_pid, filemon->fname1); 210 filemon_output(filemon, filemon->msgbufr, len); 211 } 212 if (uap->flag & O_RDWR) { 213 /* 214 * We'll get the W record below, but need 215 * to also output an R to distingish from 216 * O_WRONLY. 217 */ 218 len = snprintf(filemon->msgbufr, 219 sizeof(filemon->msgbufr), "R %d %s%s\n", 220 curproc->p_pid, filemon->fname2, filemon->fname1); 221 filemon_output(filemon, filemon->msgbufr, len); 222 } 223 224 225 len = snprintf(filemon->msgbufr, 226 sizeof(filemon->msgbufr), "%c %d %s%s\n", 227 (uap->flag & O_ACCMODE) ? 'W':'R', 228 curproc->p_pid, filemon->fname2, filemon->fname1); 229 filemon_output(filemon, filemon->msgbufr, len); 230 231 sx_xunlock(&filemon->lock); 232 } 233 } 234 235 return (ret); 236 } 237 238 static int 239 filemon_wrapper_rename(struct thread *td, struct rename_args *uap) 240 { 241 int ret; 242 size_t done; 243 size_t len; 244 struct filemon *filemon; 245 246 if ((ret = sys_rename(td, uap)) == 0) { 247 if ((filemon = filemon_pid_check(curproc)) != NULL) { 248 copyinstr(uap->from, filemon->fname1, 249 sizeof(filemon->fname1), &done); 250 copyinstr(uap->to, filemon->fname2, 251 sizeof(filemon->fname2), &done); 252 253 len = snprintf(filemon->msgbufr, 254 sizeof(filemon->msgbufr), "M %d '%s' '%s'\n", 255 curproc->p_pid, filemon->fname1, filemon->fname2); 256 257 filemon_output(filemon, filemon->msgbufr, len); 258 259 sx_xunlock(&filemon->lock); 260 } 261 } 262 263 return (ret); 264 } 265 266 static int 267 filemon_wrapper_link(struct thread *td, struct link_args *uap) 268 { 269 int ret; 270 size_t done; 271 size_t len; 272 struct filemon *filemon; 273 274 if ((ret = sys_link(td, uap)) == 0) { 275 if ((filemon = filemon_pid_check(curproc)) != NULL) { 276 copyinstr(uap->path, filemon->fname1, 277 sizeof(filemon->fname1), &done); 278 copyinstr(uap->link, filemon->fname2, 279 sizeof(filemon->fname2), &done); 280 281 len = snprintf(filemon->msgbufr, 282 sizeof(filemon->msgbufr), "L %d '%s' '%s'\n", 283 curproc->p_pid, filemon->fname1, filemon->fname2); 284 285 filemon_output(filemon, filemon->msgbufr, len); 286 287 sx_xunlock(&filemon->lock); 288 } 289 } 290 291 return (ret); 292 } 293 294 static int 295 filemon_wrapper_symlink(struct thread *td, struct symlink_args *uap) 296 { 297 int ret; 298 size_t done; 299 size_t len; 300 struct filemon *filemon; 301 302 if ((ret = sys_symlink(td, uap)) == 0) { 303 if ((filemon = filemon_pid_check(curproc)) != NULL) { 304 copyinstr(uap->path, filemon->fname1, 305 sizeof(filemon->fname1), &done); 306 copyinstr(uap->link, filemon->fname2, 307 sizeof(filemon->fname2), &done); 308 309 len = snprintf(filemon->msgbufr, 310 sizeof(filemon->msgbufr), "L %d '%s' '%s'\n", 311 curproc->p_pid, filemon->fname1, filemon->fname2); 312 313 filemon_output(filemon, filemon->msgbufr, len); 314 315 sx_xunlock(&filemon->lock); 316 } 317 } 318 319 return (ret); 320 } 321 322 static int 323 filemon_wrapper_linkat(struct thread *td, struct linkat_args *uap) 324 { 325 int ret; 326 size_t done; 327 size_t len; 328 struct filemon *filemon; 329 330 if ((ret = sys_linkat(td, uap)) == 0) { 331 if ((filemon = filemon_pid_check(curproc)) != NULL) { 332 copyinstr(uap->path1, filemon->fname1, 333 sizeof(filemon->fname1), &done); 334 copyinstr(uap->path2, filemon->fname2, 335 sizeof(filemon->fname2), &done); 336 337 len = snprintf(filemon->msgbufr, 338 sizeof(filemon->msgbufr), "L %d '%s' '%s'\n", 339 curproc->p_pid, filemon->fname1, filemon->fname2); 340 341 filemon_output(filemon, filemon->msgbufr, len); 342 343 sx_xunlock(&filemon->lock); 344 } 345 } 346 347 return (ret); 348 } 349 350 static int 351 filemon_wrapper_stat(struct thread *td, struct stat_args *uap) 352 { 353 int ret; 354 size_t done; 355 size_t len; 356 struct filemon *filemon; 357 358 if ((ret = sys_stat(td, uap)) == 0) { 359 if ((filemon = filemon_pid_check(curproc)) != NULL) { 360 copyinstr(uap->path, filemon->fname1, 361 sizeof(filemon->fname1), &done); 362 363 len = snprintf(filemon->msgbufr, 364 sizeof(filemon->msgbufr), "S %d %s\n", 365 curproc->p_pid, filemon->fname1); 366 367 filemon_output(filemon, filemon->msgbufr, len); 368 369 sx_xunlock(&filemon->lock); 370 } 371 } 372 373 return (ret); 374 } 375 376 #if defined(COMPAT_IA32) || defined(COMPAT_FREEBSD32) || defined(COMPAT_ARCH32) 377 static int 378 filemon_wrapper_freebsd32_stat(struct thread *td, 379 struct freebsd32_stat_args *uap) 380 { 381 int ret; 382 size_t done; 383 size_t len; 384 struct filemon *filemon; 385 386 if ((ret = freebsd32_stat(td, uap)) == 0) { 387 if ((filemon = filemon_pid_check(curproc)) != NULL) { 388 copyinstr(uap->path, filemon->fname1, 389 sizeof(filemon->fname1), &done); 390 391 len = snprintf(filemon->msgbufr, 392 sizeof(filemon->msgbufr), "S %d %s\n", 393 curproc->p_pid, filemon->fname1); 394 395 filemon_output(filemon, filemon->msgbufr, len); 396 397 sx_xunlock(&filemon->lock); 398 } 399 } 400 401 return (ret); 402 } 403 #endif 404 405 static void 406 filemon_event_process_exit(void *arg __unused, struct proc *p) 407 { 408 size_t len; 409 struct filemon *filemon; 410 struct timeval now; 411 412 /* Get timestamp before locking. */ 413 getmicrotime(&now); 414 415 if ((filemon = filemon_pid_check(p)) != NULL) { 416 len = snprintf(filemon->msgbufr, sizeof(filemon->msgbufr), 417 "X %d %d %d\n", p->p_pid, p->p_xexit, p->p_xsig); 418 419 filemon_output(filemon, filemon->msgbufr, len); 420 421 /* Check if the monitored process is about to exit. */ 422 if (filemon->p == p) { 423 len = snprintf(filemon->msgbufr, 424 sizeof(filemon->msgbufr), 425 "# Stop %ju.%06ju\n# Bye bye\n", 426 (uintmax_t)now.tv_sec, (uintmax_t)now.tv_usec); 427 428 filemon_output(filemon, filemon->msgbufr, len); 429 filemon->p = NULL; 430 } 431 432 sx_xunlock(&filemon->lock); 433 } 434 } 435 436 static int 437 filemon_wrapper_unlink(struct thread *td, struct unlink_args *uap) 438 { 439 int ret; 440 size_t done; 441 size_t len; 442 struct filemon *filemon; 443 444 if ((ret = sys_unlink(td, uap)) == 0) { 445 if ((filemon = filemon_pid_check(curproc)) != NULL) { 446 copyinstr(uap->path, filemon->fname1, 447 sizeof(filemon->fname1), &done); 448 449 len = snprintf(filemon->msgbufr, 450 sizeof(filemon->msgbufr), "D %d %s\n", 451 curproc->p_pid, filemon->fname1); 452 453 filemon_output(filemon, filemon->msgbufr, len); 454 455 sx_xunlock(&filemon->lock); 456 } 457 } 458 459 return (ret); 460 } 461 462 static void 463 filemon_event_process_fork(void *arg __unused, struct proc *p1, 464 struct proc *p2, int flags __unused) 465 { 466 size_t len; 467 struct filemon *filemon; 468 469 if ((filemon = filemon_pid_check(p1)) != NULL) { 470 len = snprintf(filemon->msgbufr, 471 sizeof(filemon->msgbufr), "F %d %d\n", 472 p1->p_pid, p2->p_pid); 473 474 filemon_output(filemon, filemon->msgbufr, len); 475 476 sx_xunlock(&filemon->lock); 477 } 478 } 479 480 static void 481 filemon_wrapper_install(void) 482 { 483 #if defined(__LP64__) 484 struct sysent *sv_table = elf64_freebsd_sysvec.sv_table; 485 #else 486 struct sysent *sv_table = elf32_freebsd_sysvec.sv_table; 487 #endif 488 489 sv_table[SYS_chdir].sy_call = (sy_call_t *) filemon_wrapper_chdir; 490 sv_table[SYS_open].sy_call = (sy_call_t *) filemon_wrapper_open; 491 sv_table[SYS_openat].sy_call = (sy_call_t *) filemon_wrapper_openat; 492 sv_table[SYS_rename].sy_call = (sy_call_t *) filemon_wrapper_rename; 493 sv_table[SYS_stat].sy_call = (sy_call_t *) filemon_wrapper_stat; 494 sv_table[SYS_unlink].sy_call = (sy_call_t *) filemon_wrapper_unlink; 495 sv_table[SYS_link].sy_call = (sy_call_t *) filemon_wrapper_link; 496 sv_table[SYS_symlink].sy_call = (sy_call_t *) filemon_wrapper_symlink; 497 sv_table[SYS_linkat].sy_call = (sy_call_t *) filemon_wrapper_linkat; 498 499 #if defined(COMPAT_IA32) || defined(COMPAT_FREEBSD32) || defined(COMPAT_ARCH32) 500 sv_table = ia32_freebsd_sysvec.sv_table; 501 502 sv_table[FREEBSD32_SYS_chdir].sy_call = (sy_call_t *) filemon_wrapper_chdir; 503 sv_table[FREEBSD32_SYS_open].sy_call = (sy_call_t *) filemon_wrapper_open; 504 sv_table[FREEBSD32_SYS_openat].sy_call = (sy_call_t *) filemon_wrapper_openat; 505 sv_table[FREEBSD32_SYS_rename].sy_call = (sy_call_t *) filemon_wrapper_rename; 506 sv_table[FREEBSD32_SYS_freebsd32_stat].sy_call = (sy_call_t *) filemon_wrapper_freebsd32_stat; 507 sv_table[FREEBSD32_SYS_unlink].sy_call = (sy_call_t *) filemon_wrapper_unlink; 508 sv_table[FREEBSD32_SYS_link].sy_call = (sy_call_t *) filemon_wrapper_link; 509 sv_table[FREEBSD32_SYS_symlink].sy_call = (sy_call_t *) filemon_wrapper_symlink; 510 sv_table[FREEBSD32_SYS_linkat].sy_call = (sy_call_t *) filemon_wrapper_linkat; 511 #endif /* COMPAT_ARCH32 */ 512 513 filemon_exec_tag = EVENTHANDLER_REGISTER(process_exec, 514 filemon_event_process_exec, NULL, EVENTHANDLER_PRI_LAST); 515 filemon_exit_tag = EVENTHANDLER_REGISTER(process_exit, 516 filemon_event_process_exit, NULL, EVENTHANDLER_PRI_LAST); 517 filemon_fork_tag = EVENTHANDLER_REGISTER(process_fork, 518 filemon_event_process_fork, NULL, EVENTHANDLER_PRI_LAST); 519 } 520 521 static void 522 filemon_wrapper_deinstall(void) 523 { 524 #if defined(__LP64__) 525 struct sysent *sv_table = elf64_freebsd_sysvec.sv_table; 526 #else 527 struct sysent *sv_table = elf32_freebsd_sysvec.sv_table; 528 #endif 529 530 sv_table[SYS_chdir].sy_call = (sy_call_t *)sys_chdir; 531 sv_table[SYS_open].sy_call = (sy_call_t *)sys_open; 532 sv_table[SYS_openat].sy_call = (sy_call_t *)sys_openat; 533 sv_table[SYS_rename].sy_call = (sy_call_t *)sys_rename; 534 sv_table[SYS_stat].sy_call = (sy_call_t *)sys_stat; 535 sv_table[SYS_unlink].sy_call = (sy_call_t *)sys_unlink; 536 sv_table[SYS_link].sy_call = (sy_call_t *)sys_link; 537 sv_table[SYS_symlink].sy_call = (sy_call_t *)sys_symlink; 538 sv_table[SYS_linkat].sy_call = (sy_call_t *)sys_linkat; 539 540 #if defined(COMPAT_IA32) || defined(COMPAT_FREEBSD32) || defined(COMPAT_ARCH32) 541 sv_table = ia32_freebsd_sysvec.sv_table; 542 543 sv_table[FREEBSD32_SYS_chdir].sy_call = (sy_call_t *)sys_chdir; 544 sv_table[FREEBSD32_SYS_open].sy_call = (sy_call_t *)sys_open; 545 sv_table[FREEBSD32_SYS_openat].sy_call = (sy_call_t *)sys_openat; 546 sv_table[FREEBSD32_SYS_rename].sy_call = (sy_call_t *)sys_rename; 547 sv_table[FREEBSD32_SYS_freebsd32_stat].sy_call = (sy_call_t *)freebsd32_stat; 548 sv_table[FREEBSD32_SYS_unlink].sy_call = (sy_call_t *)sys_unlink; 549 sv_table[FREEBSD32_SYS_link].sy_call = (sy_call_t *)sys_link; 550 sv_table[FREEBSD32_SYS_symlink].sy_call = (sy_call_t *)sys_symlink; 551 sv_table[FREEBSD32_SYS_linkat].sy_call = (sy_call_t *)sys_linkat; 552 #endif /* COMPAT_ARCH32 */ 553 554 EVENTHANDLER_DEREGISTER(process_exec, filemon_exec_tag); 555 EVENTHANDLER_DEREGISTER(process_exit, filemon_exit_tag); 556 EVENTHANDLER_DEREGISTER(process_fork, filemon_fork_tag); 557 } 558