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