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 filemon_filemon_lock(filemon); 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 /* Unlock the found filemon structure. */ 114 filemon_filemon_unlock(filemon); 115 } 116 } 117 118 return (ret); 119 } 120 121 static void 122 filemon_event_process_exec(void *arg __unused, struct proc *p, 123 struct image_params *imgp) 124 { 125 struct filemon *filemon; 126 char *fullpath, *freepath; 127 size_t len; 128 129 if ((filemon = filemon_pid_check(p)) != NULL) { 130 fullpath = "<unknown>"; 131 freepath = NULL; 132 133 vn_fullpath(FIRST_THREAD_IN_PROC(p), imgp->vp, &fullpath, 134 &freepath); 135 136 len = snprintf(filemon->msgbufr, 137 sizeof(filemon->msgbufr), "E %d %s\n", 138 p->p_pid, fullpath); 139 140 filemon_output(filemon, filemon->msgbufr, len); 141 142 /* Unlock the found filemon structure. */ 143 filemon_filemon_unlock(filemon); 144 145 free(freepath, M_TEMP); 146 } 147 } 148 149 static int 150 filemon_wrapper_open(struct thread *td, struct open_args *uap) 151 { 152 int ret; 153 size_t done; 154 size_t len; 155 struct filemon *filemon; 156 157 if ((ret = sys_open(td, uap)) == 0) { 158 if ((filemon = filemon_pid_check(curproc)) != NULL) { 159 copyinstr(uap->path, filemon->fname1, 160 sizeof(filemon->fname1), &done); 161 162 if (uap->flags & O_RDWR) { 163 /* 164 * We'll get the W record below, but need 165 * to also output an R to distingish from 166 * O_WRONLY. 167 */ 168 len = snprintf(filemon->msgbufr, 169 sizeof(filemon->msgbufr), "R %d %s\n", 170 curproc->p_pid, filemon->fname1); 171 filemon_output(filemon, filemon->msgbufr, len); 172 } 173 174 175 len = snprintf(filemon->msgbufr, 176 sizeof(filemon->msgbufr), "%c %d %s\n", 177 (uap->flags & O_ACCMODE) ? 'W':'R', 178 curproc->p_pid, filemon->fname1); 179 filemon_output(filemon, filemon->msgbufr, len); 180 181 /* Unlock the found filemon structure. */ 182 filemon_filemon_unlock(filemon); 183 } 184 } 185 186 return (ret); 187 } 188 189 static int 190 filemon_wrapper_openat(struct thread *td, struct openat_args *uap) 191 { 192 int ret; 193 size_t done; 194 size_t len; 195 struct filemon *filemon; 196 197 if ((ret = sys_openat(td, uap)) == 0) { 198 if ((filemon = filemon_pid_check(curproc)) != NULL) { 199 copyinstr(uap->path, filemon->fname1, 200 sizeof(filemon->fname1), &done); 201 202 filemon->fname2[0] = '\0'; 203 if (filemon->fname1[0] != '/' && uap->fd != AT_FDCWD) { 204 /* 205 * rats - we cannot do too much about this. 206 * the trace should show a dir we read 207 * recently.. output an A record as a clue 208 * until we can do better. 209 */ 210 len = snprintf(filemon->msgbufr, 211 sizeof(filemon->msgbufr), "A %d %s\n", 212 curproc->p_pid, filemon->fname1); 213 filemon_output(filemon, filemon->msgbufr, len); 214 } 215 if (uap->flag & O_RDWR) { 216 /* 217 * We'll get the W record below, but need 218 * to also output an R to distingish from 219 * O_WRONLY. 220 */ 221 len = snprintf(filemon->msgbufr, 222 sizeof(filemon->msgbufr), "R %d %s%s\n", 223 curproc->p_pid, filemon->fname2, filemon->fname1); 224 filemon_output(filemon, filemon->msgbufr, len); 225 } 226 227 228 len = snprintf(filemon->msgbufr, 229 sizeof(filemon->msgbufr), "%c %d %s%s\n", 230 (uap->flag & O_ACCMODE) ? 'W':'R', 231 curproc->p_pid, filemon->fname2, filemon->fname1); 232 filemon_output(filemon, filemon->msgbufr, len); 233 234 /* Unlock the found filemon structure. */ 235 filemon_filemon_unlock(filemon); 236 } 237 } 238 239 return (ret); 240 } 241 242 static int 243 filemon_wrapper_rename(struct thread *td, struct rename_args *uap) 244 { 245 int ret; 246 size_t done; 247 size_t len; 248 struct filemon *filemon; 249 250 if ((ret = sys_rename(td, uap)) == 0) { 251 if ((filemon = filemon_pid_check(curproc)) != NULL) { 252 copyinstr(uap->from, filemon->fname1, 253 sizeof(filemon->fname1), &done); 254 copyinstr(uap->to, filemon->fname2, 255 sizeof(filemon->fname2), &done); 256 257 len = snprintf(filemon->msgbufr, 258 sizeof(filemon->msgbufr), "M %d '%s' '%s'\n", 259 curproc->p_pid, filemon->fname1, filemon->fname2); 260 261 filemon_output(filemon, filemon->msgbufr, len); 262 263 /* Unlock the found filemon structure. */ 264 filemon_filemon_unlock(filemon); 265 } 266 } 267 268 return (ret); 269 } 270 271 static int 272 filemon_wrapper_link(struct thread *td, struct link_args *uap) 273 { 274 int ret; 275 size_t done; 276 size_t len; 277 struct filemon *filemon; 278 279 if ((ret = sys_link(td, uap)) == 0) { 280 if ((filemon = filemon_pid_check(curproc)) != NULL) { 281 copyinstr(uap->path, filemon->fname1, 282 sizeof(filemon->fname1), &done); 283 copyinstr(uap->link, filemon->fname2, 284 sizeof(filemon->fname2), &done); 285 286 len = snprintf(filemon->msgbufr, 287 sizeof(filemon->msgbufr), "L %d '%s' '%s'\n", 288 curproc->p_pid, filemon->fname1, filemon->fname2); 289 290 filemon_output(filemon, filemon->msgbufr, len); 291 292 /* Unlock the found filemon structure. */ 293 filemon_filemon_unlock(filemon); 294 } 295 } 296 297 return (ret); 298 } 299 300 static int 301 filemon_wrapper_symlink(struct thread *td, struct symlink_args *uap) 302 { 303 int ret; 304 size_t done; 305 size_t len; 306 struct filemon *filemon; 307 308 if ((ret = sys_symlink(td, uap)) == 0) { 309 if ((filemon = filemon_pid_check(curproc)) != NULL) { 310 copyinstr(uap->path, filemon->fname1, 311 sizeof(filemon->fname1), &done); 312 copyinstr(uap->link, filemon->fname2, 313 sizeof(filemon->fname2), &done); 314 315 len = snprintf(filemon->msgbufr, 316 sizeof(filemon->msgbufr), "L %d '%s' '%s'\n", 317 curproc->p_pid, filemon->fname1, filemon->fname2); 318 319 filemon_output(filemon, filemon->msgbufr, len); 320 321 /* Unlock the found filemon structure. */ 322 filemon_filemon_unlock(filemon); 323 } 324 } 325 326 return (ret); 327 } 328 329 static int 330 filemon_wrapper_linkat(struct thread *td, struct linkat_args *uap) 331 { 332 int ret; 333 size_t done; 334 size_t len; 335 struct filemon *filemon; 336 337 if ((ret = sys_linkat(td, uap)) == 0) { 338 if ((filemon = filemon_pid_check(curproc)) != NULL) { 339 copyinstr(uap->path1, filemon->fname1, 340 sizeof(filemon->fname1), &done); 341 copyinstr(uap->path2, filemon->fname2, 342 sizeof(filemon->fname2), &done); 343 344 len = snprintf(filemon->msgbufr, 345 sizeof(filemon->msgbufr), "L %d '%s' '%s'\n", 346 curproc->p_pid, filemon->fname1, filemon->fname2); 347 348 filemon_output(filemon, filemon->msgbufr, len); 349 350 /* Unlock the found filemon structure. */ 351 filemon_filemon_unlock(filemon); 352 } 353 } 354 355 return (ret); 356 } 357 358 static int 359 filemon_wrapper_stat(struct thread *td, struct stat_args *uap) 360 { 361 int ret; 362 size_t done; 363 size_t len; 364 struct filemon *filemon; 365 366 if ((ret = sys_stat(td, uap)) == 0) { 367 if ((filemon = filemon_pid_check(curproc)) != NULL) { 368 copyinstr(uap->path, filemon->fname1, 369 sizeof(filemon->fname1), &done); 370 371 len = snprintf(filemon->msgbufr, 372 sizeof(filemon->msgbufr), "S %d %s\n", 373 curproc->p_pid, filemon->fname1); 374 375 filemon_output(filemon, filemon->msgbufr, len); 376 377 /* Unlock the found filemon structure. */ 378 filemon_filemon_unlock(filemon); 379 } 380 } 381 382 return (ret); 383 } 384 385 #if defined(COMPAT_IA32) || defined(COMPAT_FREEBSD32) || defined(COMPAT_ARCH32) 386 static int 387 filemon_wrapper_freebsd32_stat(struct thread *td, 388 struct freebsd32_stat_args *uap) 389 { 390 int ret; 391 size_t done; 392 size_t len; 393 struct filemon *filemon; 394 395 if ((ret = freebsd32_stat(td, uap)) == 0) { 396 if ((filemon = filemon_pid_check(curproc)) != NULL) { 397 copyinstr(uap->path, filemon->fname1, 398 sizeof(filemon->fname1), &done); 399 400 len = snprintf(filemon->msgbufr, 401 sizeof(filemon->msgbufr), "S %d %s\n", 402 curproc->p_pid, filemon->fname1); 403 404 filemon_output(filemon, filemon->msgbufr, len); 405 406 /* Unlock the found filemon structure. */ 407 filemon_filemon_unlock(filemon); 408 } 409 } 410 411 return (ret); 412 } 413 #endif 414 415 static void 416 filemon_event_process_exit(void *arg __unused, struct proc *p) 417 { 418 size_t len; 419 struct filemon *filemon; 420 struct timeval now; 421 422 /* Get timestamp before locking. */ 423 getmicrotime(&now); 424 425 if ((filemon = filemon_pid_check(p)) != NULL) { 426 len = snprintf(filemon->msgbufr, sizeof(filemon->msgbufr), 427 "X %d %d %d\n", p->p_pid, p->p_xexit, p->p_xsig); 428 429 filemon_output(filemon, filemon->msgbufr, len); 430 431 /* Check if the monitored process is about to exit. */ 432 if (filemon->p == p) { 433 len = snprintf(filemon->msgbufr, 434 sizeof(filemon->msgbufr), 435 "# Stop %ju.%06ju\n# Bye bye\n", 436 (uintmax_t)now.tv_sec, (uintmax_t)now.tv_usec); 437 438 filemon_output(filemon, filemon->msgbufr, len); 439 filemon->p = NULL; 440 } 441 442 /* Unlock the found filemon structure. */ 443 filemon_filemon_unlock(filemon); 444 } 445 } 446 447 static int 448 filemon_wrapper_unlink(struct thread *td, struct unlink_args *uap) 449 { 450 int ret; 451 size_t done; 452 size_t len; 453 struct filemon *filemon; 454 455 if ((ret = sys_unlink(td, uap)) == 0) { 456 if ((filemon = filemon_pid_check(curproc)) != NULL) { 457 copyinstr(uap->path, filemon->fname1, 458 sizeof(filemon->fname1), &done); 459 460 len = snprintf(filemon->msgbufr, 461 sizeof(filemon->msgbufr), "D %d %s\n", 462 curproc->p_pid, filemon->fname1); 463 464 filemon_output(filemon, filemon->msgbufr, len); 465 466 /* Unlock the found filemon structure. */ 467 filemon_filemon_unlock(filemon); 468 } 469 } 470 471 return (ret); 472 } 473 474 static void 475 filemon_event_process_fork(void *arg __unused, struct proc *p1, 476 struct proc *p2, int flags __unused) 477 { 478 size_t len; 479 struct filemon *filemon; 480 481 if ((filemon = filemon_pid_check(p1)) != NULL) { 482 len = snprintf(filemon->msgbufr, 483 sizeof(filemon->msgbufr), "F %d %d\n", 484 p1->p_pid, p2->p_pid); 485 486 filemon_output(filemon, filemon->msgbufr, len); 487 488 /* Unlock the found filemon structure. */ 489 filemon_filemon_unlock(filemon); 490 } 491 } 492 493 static void 494 filemon_wrapper_install(void) 495 { 496 #if defined(__LP64__) 497 struct sysent *sv_table = elf64_freebsd_sysvec.sv_table; 498 #else 499 struct sysent *sv_table = elf32_freebsd_sysvec.sv_table; 500 #endif 501 502 sv_table[SYS_chdir].sy_call = (sy_call_t *) filemon_wrapper_chdir; 503 sv_table[SYS_open].sy_call = (sy_call_t *) filemon_wrapper_open; 504 sv_table[SYS_openat].sy_call = (sy_call_t *) filemon_wrapper_openat; 505 sv_table[SYS_rename].sy_call = (sy_call_t *) filemon_wrapper_rename; 506 sv_table[SYS_stat].sy_call = (sy_call_t *) filemon_wrapper_stat; 507 sv_table[SYS_unlink].sy_call = (sy_call_t *) filemon_wrapper_unlink; 508 sv_table[SYS_link].sy_call = (sy_call_t *) filemon_wrapper_link; 509 sv_table[SYS_symlink].sy_call = (sy_call_t *) filemon_wrapper_symlink; 510 sv_table[SYS_linkat].sy_call = (sy_call_t *) filemon_wrapper_linkat; 511 512 #if defined(COMPAT_IA32) || defined(COMPAT_FREEBSD32) || defined(COMPAT_ARCH32) 513 sv_table = ia32_freebsd_sysvec.sv_table; 514 515 sv_table[FREEBSD32_SYS_chdir].sy_call = (sy_call_t *) filemon_wrapper_chdir; 516 sv_table[FREEBSD32_SYS_open].sy_call = (sy_call_t *) filemon_wrapper_open; 517 sv_table[FREEBSD32_SYS_openat].sy_call = (sy_call_t *) filemon_wrapper_openat; 518 sv_table[FREEBSD32_SYS_rename].sy_call = (sy_call_t *) filemon_wrapper_rename; 519 sv_table[FREEBSD32_SYS_freebsd32_stat].sy_call = (sy_call_t *) filemon_wrapper_freebsd32_stat; 520 sv_table[FREEBSD32_SYS_unlink].sy_call = (sy_call_t *) filemon_wrapper_unlink; 521 sv_table[FREEBSD32_SYS_link].sy_call = (sy_call_t *) filemon_wrapper_link; 522 sv_table[FREEBSD32_SYS_symlink].sy_call = (sy_call_t *) filemon_wrapper_symlink; 523 sv_table[FREEBSD32_SYS_linkat].sy_call = (sy_call_t *) filemon_wrapper_linkat; 524 #endif /* COMPAT_ARCH32 */ 525 526 filemon_exec_tag = EVENTHANDLER_REGISTER(process_exec, 527 filemon_event_process_exec, NULL, EVENTHANDLER_PRI_LAST); 528 filemon_exit_tag = EVENTHANDLER_REGISTER(process_exit, 529 filemon_event_process_exit, NULL, EVENTHANDLER_PRI_LAST); 530 filemon_fork_tag = EVENTHANDLER_REGISTER(process_fork, 531 filemon_event_process_fork, NULL, EVENTHANDLER_PRI_LAST); 532 } 533 534 static void 535 filemon_wrapper_deinstall(void) 536 { 537 #if defined(__LP64__) 538 struct sysent *sv_table = elf64_freebsd_sysvec.sv_table; 539 #else 540 struct sysent *sv_table = elf32_freebsd_sysvec.sv_table; 541 #endif 542 543 sv_table[SYS_chdir].sy_call = (sy_call_t *)sys_chdir; 544 sv_table[SYS_open].sy_call = (sy_call_t *)sys_open; 545 sv_table[SYS_openat].sy_call = (sy_call_t *)sys_openat; 546 sv_table[SYS_rename].sy_call = (sy_call_t *)sys_rename; 547 sv_table[SYS_stat].sy_call = (sy_call_t *)sys_stat; 548 sv_table[SYS_unlink].sy_call = (sy_call_t *)sys_unlink; 549 sv_table[SYS_link].sy_call = (sy_call_t *)sys_link; 550 sv_table[SYS_symlink].sy_call = (sy_call_t *)sys_symlink; 551 sv_table[SYS_linkat].sy_call = (sy_call_t *)sys_linkat; 552 553 #if defined(COMPAT_IA32) || defined(COMPAT_FREEBSD32) || defined(COMPAT_ARCH32) 554 sv_table = ia32_freebsd_sysvec.sv_table; 555 556 sv_table[FREEBSD32_SYS_chdir].sy_call = (sy_call_t *)sys_chdir; 557 sv_table[FREEBSD32_SYS_open].sy_call = (sy_call_t *)sys_open; 558 sv_table[FREEBSD32_SYS_openat].sy_call = (sy_call_t *)sys_openat; 559 sv_table[FREEBSD32_SYS_rename].sy_call = (sy_call_t *)sys_rename; 560 sv_table[FREEBSD32_SYS_freebsd32_stat].sy_call = (sy_call_t *)freebsd32_stat; 561 sv_table[FREEBSD32_SYS_unlink].sy_call = (sy_call_t *)sys_unlink; 562 sv_table[FREEBSD32_SYS_link].sy_call = (sy_call_t *)sys_link; 563 sv_table[FREEBSD32_SYS_symlink].sy_call = (sy_call_t *)sys_symlink; 564 sv_table[FREEBSD32_SYS_linkat].sy_call = (sy_call_t *)sys_linkat; 565 #endif /* COMPAT_ARCH32 */ 566 567 EVENTHANDLER_DEREGISTER(process_exec, filemon_exec_tag); 568 EVENTHANDLER_DEREGISTER(process_exit, filemon_exit_tag); 569 EVENTHANDLER_DEREGISTER(process_fork, filemon_fork_tag); 570 } 571