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