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