1eb9aea5aSDavid E. O'Brien /*- 2eb9aea5aSDavid E. O'Brien * Copyright (c) 2011, David E. O'Brien. 3eb9aea5aSDavid E. O'Brien * Copyright (c) 2009-2011, Juniper Networks, Inc. 4e0d84b9eSBryan Drewery * Copyright (c) 2015-2016, EMC Corp. 5eb9aea5aSDavid E. O'Brien * All rights reserved. 6eb9aea5aSDavid E. O'Brien * 7eb9aea5aSDavid E. O'Brien * Redistribution and use in source and binary forms, with or without 8eb9aea5aSDavid E. O'Brien * modification, are permitted provided that the following conditions 9eb9aea5aSDavid E. O'Brien * are met: 10eb9aea5aSDavid E. O'Brien * 1. Redistributions of source code must retain the above copyright 11eb9aea5aSDavid E. O'Brien * notice, this list of conditions and the following disclaimer. 12eb9aea5aSDavid E. O'Brien * 2. Redistributions in binary form must reproduce the above copyright 13eb9aea5aSDavid E. O'Brien * notice, this list of conditions and the following disclaimer in the 14eb9aea5aSDavid E. O'Brien * documentation and/or other materials provided with the distribution. 15eb9aea5aSDavid E. O'Brien * 16eb9aea5aSDavid E. O'Brien * THIS SOFTWARE IS PROVIDED BY JUNIPER NETWORKS AND CONTRIBUTORS ``AS IS'' AND 17eb9aea5aSDavid E. O'Brien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18eb9aea5aSDavid E. O'Brien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19eb9aea5aSDavid E. O'Brien * ARE DISCLAIMED. IN NO EVENT SHALL JUNIPER NETWORKS OR CONTRIBUTORS BE LIABLE 20eb9aea5aSDavid E. O'Brien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21eb9aea5aSDavid E. O'Brien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22eb9aea5aSDavid E. O'Brien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23eb9aea5aSDavid E. O'Brien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24eb9aea5aSDavid E. O'Brien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25eb9aea5aSDavid E. O'Brien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26eb9aea5aSDavid E. O'Brien * SUCH DAMAGE. 27eb9aea5aSDavid E. O'Brien */ 28eb9aea5aSDavid E. O'Brien 29af13de0fSJohn Baldwin #include <sys/cdefs.h> 30eb9aea5aSDavid E. O'Brien __FBSDID("$FreeBSD$"); 31eb9aea5aSDavid E. O'Brien 32f9d4b392SDavid E. O'Brien #include "opt_compat.h" 33f9d4b392SDavid E. O'Brien 34af13de0fSJohn Baldwin #include <sys/param.h> 35eb9aea5aSDavid E. O'Brien #include <sys/file.h> 36eb9aea5aSDavid E. O'Brien #include <sys/systm.h> 37eb9aea5aSDavid E. O'Brien #include <sys/buf.h> 385b83ad4bSBryan Drewery #include <sys/capsicum.h> 39eb9aea5aSDavid E. O'Brien #include <sys/condvar.h> 40eb9aea5aSDavid E. O'Brien #include <sys/conf.h> 41eb9aea5aSDavid E. O'Brien #include <sys/fcntl.h> 42eb9aea5aSDavid E. O'Brien #include <sys/ioccom.h> 43eb9aea5aSDavid E. O'Brien #include <sys/kernel.h> 448183f2e3SBryan Drewery #include <sys/lock.h> 45eb9aea5aSDavid E. O'Brien #include <sys/malloc.h> 46eb9aea5aSDavid E. O'Brien #include <sys/module.h> 47eb9aea5aSDavid E. O'Brien #include <sys/poll.h> 48eb9aea5aSDavid E. O'Brien #include <sys/proc.h> 498183f2e3SBryan Drewery #include <sys/sx.h> 50eb9aea5aSDavid E. O'Brien #include <sys/syscall.h> 51eb9aea5aSDavid E. O'Brien #include <sys/sysent.h> 52eb9aea5aSDavid E. O'Brien #include <sys/sysproto.h> 53eb9aea5aSDavid E. O'Brien #include <sys/uio.h> 54eb9aea5aSDavid E. O'Brien 55eb9aea5aSDavid E. O'Brien #include "filemon.h" 56eb9aea5aSDavid E. O'Brien 57eb9aea5aSDavid E. O'Brien #if defined(COMPAT_IA32) || defined(COMPAT_FREEBSD32) || defined(COMPAT_ARCH32) 58eb9aea5aSDavid E. O'Brien #include <compat/freebsd32/freebsd32_syscall.h> 59eb9aea5aSDavid E. O'Brien #include <compat/freebsd32/freebsd32_proto.h> 60eb9aea5aSDavid E. O'Brien 61eb9aea5aSDavid E. O'Brien extern struct sysentvec ia32_freebsd_sysvec; 62eb9aea5aSDavid E. O'Brien #endif 63eb9aea5aSDavid E. O'Brien 64eb9aea5aSDavid E. O'Brien extern struct sysentvec elf32_freebsd_sysvec; 65eb9aea5aSDavid E. O'Brien extern struct sysentvec elf64_freebsd_sysvec; 66eb9aea5aSDavid E. O'Brien 67eb9aea5aSDavid E. O'Brien static d_close_t filemon_close; 68eb9aea5aSDavid E. O'Brien static d_ioctl_t filemon_ioctl; 69eb9aea5aSDavid E. O'Brien static d_open_t filemon_open; 70eb9aea5aSDavid E. O'Brien 71eb9aea5aSDavid E. O'Brien static struct cdevsw filemon_cdevsw = { 72eb9aea5aSDavid E. O'Brien .d_version = D_VERSION, 73eb9aea5aSDavid E. O'Brien .d_close = filemon_close, 74eb9aea5aSDavid E. O'Brien .d_ioctl = filemon_ioctl, 75eb9aea5aSDavid E. O'Brien .d_open = filemon_open, 76eb9aea5aSDavid E. O'Brien .d_name = "filemon", 77eb9aea5aSDavid E. O'Brien }; 78eb9aea5aSDavid E. O'Brien 79eb9aea5aSDavid E. O'Brien MALLOC_DECLARE(M_FILEMON); 80eb9aea5aSDavid E. O'Brien MALLOC_DEFINE(M_FILEMON, "filemon", "File access monitor"); 81eb9aea5aSDavid E. O'Brien 82e0d84b9eSBryan Drewery /* 83e0d84b9eSBryan Drewery * The filemon->lock protects several things currently: 84e0d84b9eSBryan Drewery * - fname1/fname2/msgbufr are pre-allocated and used per syscall 85e0d84b9eSBryan Drewery * for logging and copyins rather than stack variables. 86e0d84b9eSBryan Drewery * - Serializing the filemon's log output. 87e0d84b9eSBryan Drewery * - Preventing inheritance or removal of the filemon into proc.p_filemon. 88e0d84b9eSBryan Drewery */ 89eb9aea5aSDavid E. O'Brien struct filemon { 90e0d84b9eSBryan Drewery struct sx lock; /* Lock for this filemon. */ 91eb9aea5aSDavid E. O'Brien struct file *fp; /* Output file pointer. */ 92eb9aea5aSDavid E. O'Brien char fname1[MAXPATHLEN]; /* Temporary filename buffer. */ 93eb9aea5aSDavid E. O'Brien char fname2[MAXPATHLEN]; /* Temporary filename buffer. */ 94eb9aea5aSDavid E. O'Brien char msgbufr[1024]; /* Output message buffer. */ 95e0d84b9eSBryan Drewery u_int refcnt; /* Pointer reference count. */ 96e0d84b9eSBryan Drewery u_int proccnt; /* Process count. */ 97eb9aea5aSDavid E. O'Brien }; 98eb9aea5aSDavid E. O'Brien 99eb9aea5aSDavid E. O'Brien static struct cdev *filemon_dev; 100e0d84b9eSBryan Drewery static void filemon_output(struct filemon *filemon, char *msg, size_t len); 101eb9aea5aSDavid E. O'Brien 102e0d84b9eSBryan Drewery static __inline struct filemon * 103e0d84b9eSBryan Drewery filemon_acquire(struct filemon *filemon) 104e0d84b9eSBryan Drewery { 105e0d84b9eSBryan Drewery 106e0d84b9eSBryan Drewery if (filemon != NULL) 107e0d84b9eSBryan Drewery refcount_acquire(&filemon->refcnt); 108e0d84b9eSBryan Drewery return (filemon); 109e0d84b9eSBryan Drewery } 110e0d84b9eSBryan Drewery 111e0d84b9eSBryan Drewery /* 112*4d9fbc55SBryan Drewery * Release a reference and free on the last one. 113e0d84b9eSBryan Drewery */ 114e0d84b9eSBryan Drewery static void 115e0d84b9eSBryan Drewery filemon_release(struct filemon *filemon) 116e0d84b9eSBryan Drewery { 117e0d84b9eSBryan Drewery 118e0d84b9eSBryan Drewery if (refcount_release(&filemon->refcnt) == 0) 119e0d84b9eSBryan Drewery return; 120e0d84b9eSBryan Drewery /* 121e0d84b9eSBryan Drewery * There are valid cases of releasing while locked, such as in 122e0d84b9eSBryan Drewery * filemon_untrack_processes, but none which are done where there 123e0d84b9eSBryan Drewery * is not at least 1 reference remaining. 124e0d84b9eSBryan Drewery */ 125e0d84b9eSBryan Drewery sx_assert(&filemon->lock, SA_UNLOCKED); 126e0d84b9eSBryan Drewery 127e0d84b9eSBryan Drewery sx_destroy(&filemon->lock); 128e0d84b9eSBryan Drewery free(filemon, M_FILEMON); 129e0d84b9eSBryan Drewery } 130e0d84b9eSBryan Drewery 131e0d84b9eSBryan Drewery /* 132e0d84b9eSBryan Drewery * Acquire the proc's p_filemon reference and lock the filemon. 133e0d84b9eSBryan Drewery * The proc's p_filemon may not match this filemon on return. 134e0d84b9eSBryan Drewery */ 135e0d84b9eSBryan Drewery static struct filemon * 136e0d84b9eSBryan Drewery filemon_proc_get(struct proc *p) 137e0d84b9eSBryan Drewery { 138e0d84b9eSBryan Drewery struct filemon *filemon; 139e0d84b9eSBryan Drewery 140e0d84b9eSBryan Drewery PROC_LOCK(p); 141e0d84b9eSBryan Drewery filemon = filemon_acquire(p->p_filemon); 142e0d84b9eSBryan Drewery PROC_UNLOCK(p); 143e0d84b9eSBryan Drewery 144e0d84b9eSBryan Drewery if (filemon == NULL) 145e0d84b9eSBryan Drewery return (NULL); 146e0d84b9eSBryan Drewery /* 147e0d84b9eSBryan Drewery * The p->p_filemon may have changed by now. That case is handled 148e0d84b9eSBryan Drewery * by the exit and fork hooks and filemon_attach_proc specially. 149e0d84b9eSBryan Drewery */ 150e0d84b9eSBryan Drewery sx_xlock(&filemon->lock); 151e0d84b9eSBryan Drewery return (filemon); 152e0d84b9eSBryan Drewery } 153e0d84b9eSBryan Drewery 154e0d84b9eSBryan Drewery /* Remove and release the filemon on the given process. */ 155e0d84b9eSBryan Drewery static void 156e0d84b9eSBryan Drewery filemon_proc_drop(struct proc *p) 157e0d84b9eSBryan Drewery { 158e0d84b9eSBryan Drewery struct filemon *filemon; 159e0d84b9eSBryan Drewery 160e0d84b9eSBryan Drewery KASSERT(p->p_filemon != NULL, ("%s: proc %p NULL p_filemon", 161e0d84b9eSBryan Drewery __func__, p)); 162e0d84b9eSBryan Drewery sx_assert(&p->p_filemon->lock, SA_XLOCKED); 163e0d84b9eSBryan Drewery PROC_LOCK(p); 164e0d84b9eSBryan Drewery filemon = p->p_filemon; 165e0d84b9eSBryan Drewery p->p_filemon = NULL; 166e0d84b9eSBryan Drewery --filemon->proccnt; 167e0d84b9eSBryan Drewery PROC_UNLOCK(p); 168e0d84b9eSBryan Drewery /* 169e0d84b9eSBryan Drewery * This should not be the last reference yet. filemon_release() 170e0d84b9eSBryan Drewery * cannot be called with filemon locked, which the caller expects 171e0d84b9eSBryan Drewery * will stay locked. 172e0d84b9eSBryan Drewery */ 173e0d84b9eSBryan Drewery KASSERT(filemon->refcnt > 1, ("%s: proc %p dropping filemon %p " 174e0d84b9eSBryan Drewery "with last reference", __func__, p, filemon)); 175e0d84b9eSBryan Drewery filemon_release(filemon); 176e0d84b9eSBryan Drewery } 177e0d84b9eSBryan Drewery 178e0d84b9eSBryan Drewery /* Unlock and release the filemon. */ 179e0d84b9eSBryan Drewery static __inline void 180e0d84b9eSBryan Drewery filemon_drop(struct filemon *filemon) 181e0d84b9eSBryan Drewery { 182e0d84b9eSBryan Drewery 183e0d84b9eSBryan Drewery sx_xunlock(&filemon->lock); 184e0d84b9eSBryan Drewery filemon_release(filemon); 185e0d84b9eSBryan Drewery } 186e0d84b9eSBryan Drewery 187eb9aea5aSDavid E. O'Brien #include "filemon_wrapper.c" 188eb9aea5aSDavid E. O'Brien 189eb9aea5aSDavid E. O'Brien static void 1902b198fe9SBryan Drewery filemon_comment(struct filemon *filemon) 1912b198fe9SBryan Drewery { 1922b198fe9SBryan Drewery int len; 1932b198fe9SBryan Drewery struct timeval now; 1942b198fe9SBryan Drewery 1952b198fe9SBryan Drewery getmicrotime(&now); 1962b198fe9SBryan Drewery 1972b198fe9SBryan Drewery len = snprintf(filemon->msgbufr, sizeof(filemon->msgbufr), 1982b198fe9SBryan Drewery "# filemon version %d\n# Target pid %d\n# Start %ju.%06ju\nV %d\n", 1992b198fe9SBryan Drewery FILEMON_VERSION, curproc->p_pid, (uintmax_t)now.tv_sec, 2002b198fe9SBryan Drewery (uintmax_t)now.tv_usec, FILEMON_VERSION); 2012b198fe9SBryan Drewery 2022b198fe9SBryan Drewery filemon_output(filemon, filemon->msgbufr, len); 2032b198fe9SBryan Drewery } 2042b198fe9SBryan Drewery 205e0d84b9eSBryan Drewery /* 206e0d84b9eSBryan Drewery * Invalidate the passed filemon in all processes. 207e0d84b9eSBryan Drewery */ 208e0d84b9eSBryan Drewery static void 209e0d84b9eSBryan Drewery filemon_untrack_processes(struct filemon *filemon) 210e0d84b9eSBryan Drewery { 211e0d84b9eSBryan Drewery struct proc *p; 212e0d84b9eSBryan Drewery 213e0d84b9eSBryan Drewery sx_assert(&filemon->lock, SA_XLOCKED); 214e0d84b9eSBryan Drewery 215e0d84b9eSBryan Drewery /* Avoid allproc loop if there is no need. */ 216e0d84b9eSBryan Drewery if (filemon->proccnt == 0) 217e0d84b9eSBryan Drewery return; 218e0d84b9eSBryan Drewery 219e0d84b9eSBryan Drewery /* 220e0d84b9eSBryan Drewery * Processes in this list won't go away while here since 221e0d84b9eSBryan Drewery * filemon_event_process_exit() will lock on filemon->lock 222e0d84b9eSBryan Drewery * which we hold. 223e0d84b9eSBryan Drewery */ 224e0d84b9eSBryan Drewery sx_slock(&allproc_lock); 225e0d84b9eSBryan Drewery FOREACH_PROC_IN_SYSTEM(p) { 226e0d84b9eSBryan Drewery /* 227e0d84b9eSBryan Drewery * No PROC_LOCK is needed to compare here since it is 228e0d84b9eSBryan Drewery * guaranteed to not change since we have its filemon 229e0d84b9eSBryan Drewery * locked. Everything that changes this p_filemon will 230e0d84b9eSBryan Drewery * be locked on it. 231e0d84b9eSBryan Drewery */ 232e0d84b9eSBryan Drewery if (p->p_filemon == filemon) 233e0d84b9eSBryan Drewery filemon_proc_drop(p); 234e0d84b9eSBryan Drewery } 235e0d84b9eSBryan Drewery sx_sunlock(&allproc_lock); 236e0d84b9eSBryan Drewery 237e0d84b9eSBryan Drewery /* 238e0d84b9eSBryan Drewery * It's possible some references were acquired but will be 239e0d84b9eSBryan Drewery * dropped shortly as they are restricted from being 240e0d84b9eSBryan Drewery * inherited. There is at least the reference in cdevpriv remaining. 241e0d84b9eSBryan Drewery */ 242e0d84b9eSBryan Drewery KASSERT(filemon->refcnt > 0, ("%s: filemon %p should have " 243e0d84b9eSBryan Drewery "references still.", __func__, filemon)); 244e0d84b9eSBryan Drewery KASSERT(filemon->proccnt == 0, ("%s: filemon %p should not have " 245e0d84b9eSBryan Drewery "attached procs still.", __func__, filemon)); 246e0d84b9eSBryan Drewery } 247e0d84b9eSBryan Drewery 248*4d9fbc55SBryan Drewery /* 249*4d9fbc55SBryan Drewery * Close out the log. 250*4d9fbc55SBryan Drewery */ 251*4d9fbc55SBryan Drewery static void 252*4d9fbc55SBryan Drewery filemon_close_log(struct filemon *filemon) 253*4d9fbc55SBryan Drewery { 254*4d9fbc55SBryan Drewery struct file *fp; 255*4d9fbc55SBryan Drewery struct timeval now; 256*4d9fbc55SBryan Drewery size_t len; 257*4d9fbc55SBryan Drewery 258*4d9fbc55SBryan Drewery sx_assert(&filemon->lock, SA_XLOCKED); 259*4d9fbc55SBryan Drewery if (filemon->fp == NULL) 260*4d9fbc55SBryan Drewery return; 261*4d9fbc55SBryan Drewery 262*4d9fbc55SBryan Drewery getmicrotime(&now); 263*4d9fbc55SBryan Drewery 264*4d9fbc55SBryan Drewery len = snprintf(filemon->msgbufr, 265*4d9fbc55SBryan Drewery sizeof(filemon->msgbufr), 266*4d9fbc55SBryan Drewery "# Stop %ju.%06ju\n# Bye bye\n", 267*4d9fbc55SBryan Drewery (uintmax_t)now.tv_sec, (uintmax_t)now.tv_usec); 268*4d9fbc55SBryan Drewery 269*4d9fbc55SBryan Drewery filemon_output(filemon, filemon->msgbufr, len); 270*4d9fbc55SBryan Drewery fp = filemon->fp; 271*4d9fbc55SBryan Drewery filemon->fp = NULL; 272*4d9fbc55SBryan Drewery 273*4d9fbc55SBryan Drewery sx_xunlock(&filemon->lock); 274*4d9fbc55SBryan Drewery fdrop(fp, curthread); 275*4d9fbc55SBryan Drewery sx_xlock(&filemon->lock); 276*4d9fbc55SBryan Drewery 277*4d9fbc55SBryan Drewery return; 278*4d9fbc55SBryan Drewery } 279e0d84b9eSBryan Drewery 280e0d84b9eSBryan Drewery /* The devfs file is being closed. Untrace all processes. */ 2812b198fe9SBryan Drewery static void 282eb9aea5aSDavid E. O'Brien filemon_dtr(void *data) 283eb9aea5aSDavid E. O'Brien { 284eb9aea5aSDavid E. O'Brien struct filemon *filemon = data; 285eb9aea5aSDavid E. O'Brien 286e0d84b9eSBryan Drewery if (filemon == NULL) 287e0d84b9eSBryan Drewery return; 288eb9aea5aSDavid E. O'Brien 289e0dae8f1SBryan Drewery sx_xlock(&filemon->lock); 290e0d84b9eSBryan Drewery /* 291*4d9fbc55SBryan Drewery * Detach the filemon. It cannot be inherited after this. 292e0d84b9eSBryan Drewery */ 293e0d84b9eSBryan Drewery filemon_untrack_processes(filemon); 294*4d9fbc55SBryan Drewery filemon_close_log(filemon); 295e0d84b9eSBryan Drewery filemon_drop(filemon); 296eb9aea5aSDavid E. O'Brien } 297e0d84b9eSBryan Drewery 298e0d84b9eSBryan Drewery /* Attach the filemon to the process. */ 299e0d84b9eSBryan Drewery static int 300e0d84b9eSBryan Drewery filemon_attach_proc(struct filemon *filemon, struct proc *p) 301e0d84b9eSBryan Drewery { 302e0d84b9eSBryan Drewery struct filemon *filemon2; 303e0d84b9eSBryan Drewery 304e0d84b9eSBryan Drewery sx_assert(&filemon->lock, SA_XLOCKED); 305e0d84b9eSBryan Drewery PROC_LOCK_ASSERT(p, MA_OWNED); 306e0d84b9eSBryan Drewery KASSERT((p->p_flag & P_WEXIT) == 0, 307e0d84b9eSBryan Drewery ("%s: filemon %p attaching to exiting process %p", 308e0d84b9eSBryan Drewery __func__, filemon, p)); 309e0d84b9eSBryan Drewery 310e0d84b9eSBryan Drewery if (p->p_filemon == filemon) 311e0d84b9eSBryan Drewery return (0); 312e0d84b9eSBryan Drewery /* 313e0d84b9eSBryan Drewery * Don't allow truncating other process traces. It is 314e0d84b9eSBryan Drewery * not really intended to trace procs other than curproc 315e0d84b9eSBryan Drewery * anyhow. 316e0d84b9eSBryan Drewery */ 317e0d84b9eSBryan Drewery if (p->p_filemon != NULL && p != curproc) 318e0d84b9eSBryan Drewery return (EBUSY); 319e0d84b9eSBryan Drewery /* 320e0d84b9eSBryan Drewery * Historic behavior of filemon has been to let a child initiate 321e0d84b9eSBryan Drewery * tracing on itself and cease existing tracing. Bmake 322e0d84b9eSBryan Drewery * .META + .MAKE relies on this. It is only relevant for attaching to 323e0d84b9eSBryan Drewery * curproc. 324e0d84b9eSBryan Drewery */ 325e0d84b9eSBryan Drewery while (p->p_filemon != NULL) { 326e0d84b9eSBryan Drewery PROC_UNLOCK(p); 327e0d84b9eSBryan Drewery sx_xunlock(&filemon->lock); 328e0d84b9eSBryan Drewery while ((filemon2 = filemon_proc_get(p)) != NULL) { 329e0d84b9eSBryan Drewery /* It may have changed. */ 330e0d84b9eSBryan Drewery if (p->p_filemon == filemon2) 331e0d84b9eSBryan Drewery filemon_proc_drop(p); 332e0d84b9eSBryan Drewery filemon_drop(filemon2); 333e0d84b9eSBryan Drewery } 334e0d84b9eSBryan Drewery sx_xlock(&filemon->lock); 335e0d84b9eSBryan Drewery PROC_LOCK(p); 336e0d84b9eSBryan Drewery /* 337e0d84b9eSBryan Drewery * It may have been attached to, though unlikely. 338e0d84b9eSBryan Drewery * Try again if needed. 339e0d84b9eSBryan Drewery */ 340e0d84b9eSBryan Drewery } 341e0d84b9eSBryan Drewery 342e0d84b9eSBryan Drewery KASSERT(p->p_filemon == NULL, 343e0d84b9eSBryan Drewery ("%s: proc %p didn't detach filemon %p", __func__, p, 344e0d84b9eSBryan Drewery p->p_filemon)); 345e0d84b9eSBryan Drewery p->p_filemon = filemon_acquire(filemon); 346e0d84b9eSBryan Drewery ++filemon->proccnt; 347e0d84b9eSBryan Drewery 348e0d84b9eSBryan Drewery return (0); 349eb9aea5aSDavid E. O'Brien } 350eb9aea5aSDavid E. O'Brien 351eb9aea5aSDavid E. O'Brien static int 352eb9aea5aSDavid E. O'Brien filemon_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag __unused, 353eb9aea5aSDavid E. O'Brien struct thread *td) 354eb9aea5aSDavid E. O'Brien { 355eb9aea5aSDavid E. O'Brien int error = 0; 356eb9aea5aSDavid E. O'Brien struct filemon *filemon; 357872ce247SHiroki Sato struct proc *p; 3587008be5bSPawel Jakub Dawidek cap_rights_t rights; 359eb9aea5aSDavid E. O'Brien 360e8c87a09SBryan Drewery if ((error = devfs_get_cdevpriv((void **) &filemon)) != 0) 361e8c87a09SBryan Drewery return (error); 362eb9aea5aSDavid E. O'Brien 363e0dae8f1SBryan Drewery sx_xlock(&filemon->lock); 36464c368a4SBryan Drewery 365eb9aea5aSDavid E. O'Brien switch (cmd) { 366eb9aea5aSDavid E. O'Brien /* Set the output file descriptor. */ 367eb9aea5aSDavid E. O'Brien case FILEMON_SET_FD: 368044fd543SBryan Drewery if (filemon->fp != NULL) { 369044fd543SBryan Drewery error = EEXIST; 370044fd543SBryan Drewery break; 371044fd543SBryan Drewery } 372fac4a7acSBryan Drewery 3737008be5bSPawel Jakub Dawidek error = fget_write(td, *(int *)data, 3747008be5bSPawel Jakub Dawidek cap_rights_init(&rights, CAP_PWRITE), 3757008be5bSPawel Jakub Dawidek &filemon->fp); 3767008be5bSPawel Jakub Dawidek if (error == 0) 377eb9aea5aSDavid E. O'Brien /* Write the file header. */ 378eb9aea5aSDavid E. O'Brien filemon_comment(filemon); 379eb9aea5aSDavid E. O'Brien break; 380eb9aea5aSDavid E. O'Brien 381eb9aea5aSDavid E. O'Brien /* Set the monitored process ID. */ 382eb9aea5aSDavid E. O'Brien case FILEMON_SET_PID: 383e0d84b9eSBryan Drewery /* Invalidate any existing processes already set. */ 384e0d84b9eSBryan Drewery filemon_untrack_processes(filemon); 385e0d84b9eSBryan Drewery 38689cac24eSHiroki Sato error = pget(*((pid_t *)data), PGET_CANDEBUG | PGET_NOTWEXIT, 38789cac24eSHiroki Sato &p); 38889cac24eSHiroki Sato if (error == 0) { 389e0d84b9eSBryan Drewery KASSERT(p->p_filemon != filemon, 390e0d84b9eSBryan Drewery ("%s: proc %p didn't untrack filemon %p", 391e0d84b9eSBryan Drewery __func__, p, filemon)); 392e0d84b9eSBryan Drewery error = filemon_attach_proc(filemon, p); 393872ce247SHiroki Sato PROC_UNLOCK(p); 39489cac24eSHiroki Sato } 395eb9aea5aSDavid E. O'Brien break; 396eb9aea5aSDavid E. O'Brien 397eb9aea5aSDavid E. O'Brien default: 398eb9aea5aSDavid E. O'Brien error = EINVAL; 399eb9aea5aSDavid E. O'Brien break; 400eb9aea5aSDavid E. O'Brien } 401eb9aea5aSDavid E. O'Brien 402e0dae8f1SBryan Drewery sx_xunlock(&filemon->lock); 403eb9aea5aSDavid E. O'Brien return (error); 404eb9aea5aSDavid E. O'Brien } 405eb9aea5aSDavid E. O'Brien 406eb9aea5aSDavid E. O'Brien static int 407eb9aea5aSDavid E. O'Brien filemon_open(struct cdev *dev, int oflags __unused, int devtype __unused, 408eb9aea5aSDavid E. O'Brien struct thread *td __unused) 409eb9aea5aSDavid E. O'Brien { 410e0d84b9eSBryan Drewery int error; 411eb9aea5aSDavid E. O'Brien struct filemon *filemon; 412eb9aea5aSDavid E. O'Brien 413e0d84b9eSBryan Drewery filemon = malloc(sizeof(*filemon), M_FILEMON, 414eb9aea5aSDavid E. O'Brien M_WAITOK | M_ZERO); 4158183f2e3SBryan Drewery sx_init(&filemon->lock, "filemon"); 416e0d84b9eSBryan Drewery refcount_init(&filemon->refcnt, 1); 417eb9aea5aSDavid E. O'Brien 418e0d84b9eSBryan Drewery error = devfs_set_cdevpriv(filemon, filemon_dtr); 419e0d84b9eSBryan Drewery if (error != 0) 420e0d84b9eSBryan Drewery filemon_release(filemon); 421eb9aea5aSDavid E. O'Brien 422e0d84b9eSBryan Drewery return (error); 423eb9aea5aSDavid E. O'Brien } 424eb9aea5aSDavid E. O'Brien 425eb9aea5aSDavid E. O'Brien static int 426eb9aea5aSDavid E. O'Brien filemon_close(struct cdev *dev __unused, int flag __unused, int fmt __unused, 427eb9aea5aSDavid E. O'Brien struct thread *td __unused) 428eb9aea5aSDavid E. O'Brien { 429eb9aea5aSDavid E. O'Brien 430eb9aea5aSDavid E. O'Brien return (0); 431eb9aea5aSDavid E. O'Brien } 432eb9aea5aSDavid E. O'Brien 433eb9aea5aSDavid E. O'Brien static void 434eb9aea5aSDavid E. O'Brien filemon_load(void *dummy __unused) 435eb9aea5aSDavid E. O'Brien { 436eb9aea5aSDavid E. O'Brien 437eb9aea5aSDavid E. O'Brien /* Install the syscall wrappers. */ 438eb9aea5aSDavid E. O'Brien filemon_wrapper_install(); 439eb9aea5aSDavid E. O'Brien 440eb9aea5aSDavid E. O'Brien filemon_dev = make_dev(&filemon_cdevsw, 0, UID_ROOT, GID_WHEEL, 0666, 441eb9aea5aSDavid E. O'Brien "filemon"); 442eb9aea5aSDavid E. O'Brien } 443eb9aea5aSDavid E. O'Brien 444eb9aea5aSDavid E. O'Brien static int 445eb9aea5aSDavid E. O'Brien filemon_unload(void) 446eb9aea5aSDavid E. O'Brien { 447eb9aea5aSDavid E. O'Brien 448eb9aea5aSDavid E. O'Brien destroy_dev(filemon_dev); 449eb9aea5aSDavid E. O'Brien filemon_wrapper_deinstall(); 450eb9aea5aSDavid E. O'Brien 451e0d84b9eSBryan Drewery return (0); 452eb9aea5aSDavid E. O'Brien } 453eb9aea5aSDavid E. O'Brien 454eb9aea5aSDavid E. O'Brien static int 455eb9aea5aSDavid E. O'Brien filemon_modevent(module_t mod __unused, int type, void *data) 456eb9aea5aSDavid E. O'Brien { 457eb9aea5aSDavid E. O'Brien int error = 0; 458eb9aea5aSDavid E. O'Brien 459eb9aea5aSDavid E. O'Brien switch (type) { 460eb9aea5aSDavid E. O'Brien case MOD_LOAD: 461eb9aea5aSDavid E. O'Brien filemon_load(data); 462eb9aea5aSDavid E. O'Brien break; 463eb9aea5aSDavid E. O'Brien 464eb9aea5aSDavid E. O'Brien case MOD_UNLOAD: 465eb9aea5aSDavid E. O'Brien error = filemon_unload(); 466eb9aea5aSDavid E. O'Brien break; 467eb9aea5aSDavid E. O'Brien 4684039c531SBryan Drewery case MOD_QUIESCE: 4694039c531SBryan Drewery /* 4704039c531SBryan Drewery * The wrapper implementation is unsafe for reliable unload. 4714039c531SBryan Drewery * Require forcing an unload. 4724039c531SBryan Drewery */ 4734039c531SBryan Drewery error = EBUSY; 4741e35cdf6SBryan Drewery break; 4754039c531SBryan Drewery 476eb9aea5aSDavid E. O'Brien case MOD_SHUTDOWN: 477eb9aea5aSDavid E. O'Brien break; 478eb9aea5aSDavid E. O'Brien 479eb9aea5aSDavid E. O'Brien default: 480eb9aea5aSDavid E. O'Brien error = EOPNOTSUPP; 481eb9aea5aSDavid E. O'Brien break; 482eb9aea5aSDavid E. O'Brien 483eb9aea5aSDavid E. O'Brien } 484eb9aea5aSDavid E. O'Brien 485eb9aea5aSDavid E. O'Brien return (error); 486eb9aea5aSDavid E. O'Brien } 487eb9aea5aSDavid E. O'Brien 488eb9aea5aSDavid E. O'Brien DEV_MODULE(filemon, filemon_modevent, NULL); 489eb9aea5aSDavid E. O'Brien MODULE_VERSION(filemon, 1); 490