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