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