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