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