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