1 /*- 2 * Copyright (c) 2011, David E. O'Brien. 3 * Copyright (c) 2009-2011, Juniper Networks, Inc. 4 * Copyright (c) 2015-2016, 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/eventhandler.h> 33 #include <sys/filedesc.h> 34 #include <sys/imgact.h> 35 #include <sys/sx.h> 36 #include <sys/vnode.h> 37 38 #include "opt_compat.h" 39 40 static eventhandler_tag filemon_exec_tag; 41 static eventhandler_tag filemon_exit_tag; 42 static eventhandler_tag filemon_fork_tag; 43 44 static void 45 filemon_output(struct filemon *filemon, char *msg, size_t len) 46 { 47 struct uio auio; 48 struct iovec aiov; 49 int error; 50 51 if (filemon->fp == NULL) 52 return; 53 54 aiov.iov_base = msg; 55 aiov.iov_len = len; 56 auio.uio_iov = &aiov; 57 auio.uio_iovcnt = 1; 58 auio.uio_resid = len; 59 auio.uio_segflg = UIO_SYSSPACE; 60 auio.uio_rw = UIO_WRITE; 61 auio.uio_td = curthread; 62 auio.uio_offset = (off_t) -1; 63 64 if (filemon->fp->f_type == DTYPE_VNODE) 65 bwillwrite(); 66 67 error = fo_write(filemon->fp, &auio, curthread->td_ucred, 0, curthread); 68 if (error != 0) 69 filemon->error = error; 70 } 71 72 static int 73 filemon_wrapper_chdir(struct thread *td, struct chdir_args *uap) 74 { 75 int error, ret; 76 size_t len; 77 struct filemon *filemon; 78 79 if ((ret = sys_chdir(td, uap)) == 0) { 80 if ((filemon = filemon_proc_get(curproc)) != NULL) { 81 if ((error = copyinstr(uap->path, filemon->fname1, 82 sizeof(filemon->fname1), NULL)) != 0) { 83 filemon->error = error; 84 goto copyfail; 85 } 86 87 len = snprintf(filemon->msgbufr, 88 sizeof(filemon->msgbufr), "C %d %s\n", 89 curproc->p_pid, filemon->fname1); 90 91 filemon_output(filemon, filemon->msgbufr, len); 92 copyfail: 93 filemon_drop(filemon); 94 } 95 } 96 97 return (ret); 98 } 99 100 static void 101 filemon_event_process_exec(void *arg __unused, struct proc *p, 102 struct image_params *imgp) 103 { 104 struct filemon *filemon; 105 char *fullpath, *freepath; 106 size_t len; 107 108 if ((filemon = filemon_proc_get(p)) != NULL) { 109 fullpath = "<unknown>"; 110 freepath = NULL; 111 112 vn_fullpath(curthread, imgp->vp, &fullpath, &freepath); 113 114 len = snprintf(filemon->msgbufr, 115 sizeof(filemon->msgbufr), "E %d %s\n", 116 p->p_pid, fullpath); 117 118 filemon_output(filemon, filemon->msgbufr, len); 119 120 filemon_drop(filemon); 121 122 free(freepath, M_TEMP); 123 } 124 } 125 126 static void 127 _filemon_wrapper_openat(struct thread *td, char *upath, int flags, int fd) 128 { 129 int error; 130 size_t len; 131 struct file *fp; 132 struct filemon *filemon; 133 char *atpath, *freepath; 134 cap_rights_t rights; 135 136 if ((filemon = filemon_proc_get(curproc)) != NULL) { 137 atpath = ""; 138 freepath = NULL; 139 fp = NULL; 140 141 if ((error = copyinstr(upath, filemon->fname1, 142 sizeof(filemon->fname1), NULL)) != 0) { 143 filemon->error = error; 144 goto copyfail; 145 } 146 147 if (filemon->fname1[0] != '/' && fd != AT_FDCWD) { 148 /* 149 * rats - we cannot do too much about this. 150 * the trace should show a dir we read 151 * recently.. output an A record as a clue 152 * until we can do better. 153 * XXX: This may be able to come out with 154 * the namecache lookup now. 155 */ 156 len = snprintf(filemon->msgbufr, 157 sizeof(filemon->msgbufr), "A %d %s\n", 158 curproc->p_pid, filemon->fname1); 159 filemon_output(filemon, filemon->msgbufr, len); 160 /* 161 * Try to resolve the path from the vnode using the 162 * namecache. It may be inaccurate, but better 163 * than nothing. 164 */ 165 if (getvnode(td, fd, 166 cap_rights_init(&rights, CAP_LOOKUP), &fp) == 0) { 167 vn_fullpath(td, fp->f_vnode, &atpath, 168 &freepath); 169 } 170 } 171 if (flags & O_RDWR) { 172 /* 173 * We'll get the W record below, but need 174 * to also output an R to distinguish from 175 * O_WRONLY. 176 */ 177 len = snprintf(filemon->msgbufr, 178 sizeof(filemon->msgbufr), "R %d %s%s%s\n", 179 curproc->p_pid, atpath, 180 atpath[0] != '\0' ? "/" : "", filemon->fname1); 181 filemon_output(filemon, filemon->msgbufr, len); 182 } 183 184 len = snprintf(filemon->msgbufr, 185 sizeof(filemon->msgbufr), "%c %d %s%s%s\n", 186 (flags & O_ACCMODE) ? 'W':'R', 187 curproc->p_pid, atpath, 188 atpath[0] != '\0' ? "/" : "", filemon->fname1); 189 filemon_output(filemon, filemon->msgbufr, len); 190 copyfail: 191 filemon_drop(filemon); 192 if (fp != NULL) 193 fdrop(fp, td); 194 free(freepath, M_TEMP); 195 } 196 } 197 198 static int 199 filemon_wrapper_open(struct thread *td, struct open_args *uap) 200 { 201 int ret; 202 203 if ((ret = sys_open(td, uap)) == 0) 204 _filemon_wrapper_openat(td, uap->path, uap->flags, AT_FDCWD); 205 206 return (ret); 207 } 208 209 static int 210 filemon_wrapper_openat(struct thread *td, struct openat_args *uap) 211 { 212 int ret; 213 214 if ((ret = sys_openat(td, uap)) == 0) 215 _filemon_wrapper_openat(td, uap->path, uap->flag, uap->fd); 216 217 return (ret); 218 } 219 220 static int 221 filemon_wrapper_rename(struct thread *td, struct rename_args *uap) 222 { 223 int error, ret; 224 size_t len; 225 struct filemon *filemon; 226 227 if ((ret = sys_rename(td, uap)) == 0) { 228 if ((filemon = filemon_proc_get(curproc)) != NULL) { 229 if (((error = copyinstr(uap->from, filemon->fname1, 230 sizeof(filemon->fname1), NULL)) != 0) || 231 ((error = copyinstr(uap->to, filemon->fname2, 232 sizeof(filemon->fname2), NULL)) != 0)) { 233 filemon->error = error; 234 goto copyfail; 235 } 236 237 len = snprintf(filemon->msgbufr, 238 sizeof(filemon->msgbufr), "M %d '%s' '%s'\n", 239 curproc->p_pid, filemon->fname1, filemon->fname2); 240 241 filemon_output(filemon, filemon->msgbufr, len); 242 copyfail: 243 filemon_drop(filemon); 244 } 245 } 246 247 return (ret); 248 } 249 250 static void 251 _filemon_wrapper_link(struct thread *td, char *upath1, char *upath2) 252 { 253 struct filemon *filemon; 254 size_t len; 255 int error; 256 257 if ((filemon = filemon_proc_get(curproc)) != NULL) { 258 if (((error = copyinstr(upath1, filemon->fname1, 259 sizeof(filemon->fname1), NULL)) != 0) || 260 ((error = copyinstr(upath2, filemon->fname2, 261 sizeof(filemon->fname2), NULL)) != 0)) { 262 filemon->error = error; 263 goto copyfail; 264 } 265 266 len = snprintf(filemon->msgbufr, 267 sizeof(filemon->msgbufr), "L %d '%s' '%s'\n", 268 curproc->p_pid, filemon->fname1, filemon->fname2); 269 270 filemon_output(filemon, filemon->msgbufr, len); 271 copyfail: 272 filemon_drop(filemon); 273 } 274 } 275 276 static int 277 filemon_wrapper_link(struct thread *td, struct link_args *uap) 278 { 279 int ret; 280 281 if ((ret = sys_link(td, uap)) == 0) 282 _filemon_wrapper_link(td, uap->path, uap->link); 283 284 return (ret); 285 } 286 287 static int 288 filemon_wrapper_symlink(struct thread *td, struct symlink_args *uap) 289 { 290 int ret; 291 292 if ((ret = sys_symlink(td, uap)) == 0) 293 _filemon_wrapper_link(td, uap->path, uap->link); 294 295 return (ret); 296 } 297 298 static int 299 filemon_wrapper_linkat(struct thread *td, struct linkat_args *uap) 300 { 301 int ret; 302 303 if ((ret = sys_linkat(td, uap)) == 0) 304 _filemon_wrapper_link(td, uap->path1, uap->path2); 305 306 return (ret); 307 } 308 309 static void 310 filemon_event_process_exit(void *arg __unused, struct proc *p) 311 { 312 size_t len; 313 struct filemon *filemon; 314 315 if ((filemon = filemon_proc_get(p)) != NULL) { 316 len = snprintf(filemon->msgbufr, sizeof(filemon->msgbufr), 317 "X %d %d %d\n", p->p_pid, p->p_xexit, p->p_xsig); 318 319 filemon_output(filemon, filemon->msgbufr, len); 320 321 /* 322 * filemon_untrack_processes() may have dropped this p_filemon 323 * already while in filemon_proc_get() before acquiring the 324 * filemon lock. 325 */ 326 KASSERT(p->p_filemon == NULL || p->p_filemon == filemon, 327 ("%s: p %p was attached while exiting, expected " 328 "filemon %p or NULL", __func__, p, filemon)); 329 if (p->p_filemon == filemon) 330 filemon_proc_drop(p); 331 332 filemon_drop(filemon); 333 } 334 } 335 336 static int 337 filemon_wrapper_unlink(struct thread *td, struct unlink_args *uap) 338 { 339 int error, ret; 340 size_t len; 341 struct filemon *filemon; 342 343 if ((ret = sys_unlink(td, uap)) == 0) { 344 if ((filemon = filemon_proc_get(curproc)) != NULL) { 345 if ((error = copyinstr(uap->path, filemon->fname1, 346 sizeof(filemon->fname1), NULL)) != 0) { 347 filemon->error = error; 348 goto copyfail; 349 } 350 351 len = snprintf(filemon->msgbufr, 352 sizeof(filemon->msgbufr), "D %d %s\n", 353 curproc->p_pid, filemon->fname1); 354 355 filemon_output(filemon, filemon->msgbufr, len); 356 copyfail: 357 filemon_drop(filemon); 358 } 359 } 360 361 return (ret); 362 } 363 364 static void 365 filemon_event_process_fork(void *arg __unused, struct proc *p1, 366 struct proc *p2, int flags __unused) 367 { 368 size_t len; 369 struct filemon *filemon; 370 371 if ((filemon = filemon_proc_get(p1)) != NULL) { 372 len = snprintf(filemon->msgbufr, 373 sizeof(filemon->msgbufr), "F %d %d\n", 374 p1->p_pid, p2->p_pid); 375 376 filemon_output(filemon, filemon->msgbufr, len); 377 378 /* 379 * filemon_untrack_processes() or 380 * filemon_ioctl(FILEMON_SET_PID) may have changed the parent's 381 * p_filemon while in filemon_proc_get() before acquiring the 382 * filemon lock. Only inherit if the parent is still traced by 383 * this filemon. 384 */ 385 if (p1->p_filemon == filemon) { 386 PROC_LOCK(p2); 387 /* 388 * It may have been attached to already by a new 389 * filemon. 390 */ 391 if (p2->p_filemon == NULL) { 392 p2->p_filemon = filemon_acquire(filemon); 393 ++filemon->proccnt; 394 } 395 PROC_UNLOCK(p2); 396 } 397 398 filemon_drop(filemon); 399 } 400 } 401 402 static void 403 filemon_wrapper_install(void) 404 { 405 #if defined(__LP64__) 406 struct sysent *sv_table = elf64_freebsd_sysvec.sv_table; 407 #else 408 struct sysent *sv_table = elf32_freebsd_sysvec.sv_table; 409 #endif 410 411 sv_table[SYS_chdir].sy_call = (sy_call_t *) filemon_wrapper_chdir; 412 sv_table[SYS_open].sy_call = (sy_call_t *) filemon_wrapper_open; 413 sv_table[SYS_openat].sy_call = (sy_call_t *) filemon_wrapper_openat; 414 sv_table[SYS_rename].sy_call = (sy_call_t *) filemon_wrapper_rename; 415 sv_table[SYS_unlink].sy_call = (sy_call_t *) filemon_wrapper_unlink; 416 sv_table[SYS_link].sy_call = (sy_call_t *) filemon_wrapper_link; 417 sv_table[SYS_symlink].sy_call = (sy_call_t *) filemon_wrapper_symlink; 418 sv_table[SYS_linkat].sy_call = (sy_call_t *) filemon_wrapper_linkat; 419 420 #if defined(COMPAT_IA32) || defined(COMPAT_FREEBSD32) || defined(COMPAT_ARCH32) 421 sv_table = ia32_freebsd_sysvec.sv_table; 422 423 sv_table[FREEBSD32_SYS_chdir].sy_call = (sy_call_t *) filemon_wrapper_chdir; 424 sv_table[FREEBSD32_SYS_open].sy_call = (sy_call_t *) filemon_wrapper_open; 425 sv_table[FREEBSD32_SYS_openat].sy_call = (sy_call_t *) filemon_wrapper_openat; 426 sv_table[FREEBSD32_SYS_rename].sy_call = (sy_call_t *) filemon_wrapper_rename; 427 sv_table[FREEBSD32_SYS_unlink].sy_call = (sy_call_t *) filemon_wrapper_unlink; 428 sv_table[FREEBSD32_SYS_link].sy_call = (sy_call_t *) filemon_wrapper_link; 429 sv_table[FREEBSD32_SYS_symlink].sy_call = (sy_call_t *) filemon_wrapper_symlink; 430 sv_table[FREEBSD32_SYS_linkat].sy_call = (sy_call_t *) filemon_wrapper_linkat; 431 #endif /* COMPAT_ARCH32 */ 432 433 filemon_exec_tag = EVENTHANDLER_REGISTER(process_exec, 434 filemon_event_process_exec, NULL, EVENTHANDLER_PRI_LAST); 435 filemon_exit_tag = EVENTHANDLER_REGISTER(process_exit, 436 filemon_event_process_exit, NULL, EVENTHANDLER_PRI_LAST); 437 filemon_fork_tag = EVENTHANDLER_REGISTER(process_fork, 438 filemon_event_process_fork, NULL, EVENTHANDLER_PRI_LAST); 439 } 440 441 static void 442 filemon_wrapper_deinstall(void) 443 { 444 #if defined(__LP64__) 445 struct sysent *sv_table = elf64_freebsd_sysvec.sv_table; 446 #else 447 struct sysent *sv_table = elf32_freebsd_sysvec.sv_table; 448 #endif 449 450 sv_table[SYS_chdir].sy_call = (sy_call_t *)sys_chdir; 451 sv_table[SYS_open].sy_call = (sy_call_t *)sys_open; 452 sv_table[SYS_openat].sy_call = (sy_call_t *)sys_openat; 453 sv_table[SYS_rename].sy_call = (sy_call_t *)sys_rename; 454 sv_table[SYS_unlink].sy_call = (sy_call_t *)sys_unlink; 455 sv_table[SYS_link].sy_call = (sy_call_t *)sys_link; 456 sv_table[SYS_symlink].sy_call = (sy_call_t *)sys_symlink; 457 sv_table[SYS_linkat].sy_call = (sy_call_t *)sys_linkat; 458 459 #if defined(COMPAT_IA32) || defined(COMPAT_FREEBSD32) || defined(COMPAT_ARCH32) 460 sv_table = ia32_freebsd_sysvec.sv_table; 461 462 sv_table[FREEBSD32_SYS_chdir].sy_call = (sy_call_t *)sys_chdir; 463 sv_table[FREEBSD32_SYS_open].sy_call = (sy_call_t *)sys_open; 464 sv_table[FREEBSD32_SYS_openat].sy_call = (sy_call_t *)sys_openat; 465 sv_table[FREEBSD32_SYS_rename].sy_call = (sy_call_t *)sys_rename; 466 sv_table[FREEBSD32_SYS_unlink].sy_call = (sy_call_t *)sys_unlink; 467 sv_table[FREEBSD32_SYS_link].sy_call = (sy_call_t *)sys_link; 468 sv_table[FREEBSD32_SYS_symlink].sy_call = (sy_call_t *)sys_symlink; 469 sv_table[FREEBSD32_SYS_linkat].sy_call = (sy_call_t *)sys_linkat; 470 #endif /* COMPAT_ARCH32 */ 471 472 EVENTHANDLER_DEREGISTER(process_exec, filemon_exec_tag); 473 EVENTHANDLER_DEREGISTER(process_exit, filemon_exit_tag); 474 EVENTHANDLER_DEREGISTER(process_fork, filemon_fork_tag); 475 } 476