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