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