kern_ktrace.c revision 104230
11541Srgrimes/* 21541Srgrimes * Copyright (c) 1989, 1993 31541Srgrimes * The Regents of the University of California. All rights reserved. 41541Srgrimes * 51541Srgrimes * Redistribution and use in source and binary forms, with or without 61541Srgrimes * modification, are permitted provided that the following conditions 71541Srgrimes * are met: 81541Srgrimes * 1. Redistributions of source code must retain the above copyright 91541Srgrimes * notice, this list of conditions and the following disclaimer. 101541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111541Srgrimes * notice, this list of conditions and the following disclaimer in the 121541Srgrimes * documentation and/or other materials provided with the distribution. 131541Srgrimes * 3. All advertising materials mentioning features or use of this software 141541Srgrimes * must display the following acknowledgement: 151541Srgrimes * This product includes software developed by the University of 161541Srgrimes * California, Berkeley and its contributors. 171541Srgrimes * 4. Neither the name of the University nor the names of its contributors 181541Srgrimes * may be used to endorse or promote products derived from this software 191541Srgrimes * without specific prior written permission. 201541Srgrimes * 211541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 221541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 231541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 241541Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 251541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 261541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 271541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 281541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 291541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 301541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 311541Srgrimes * SUCH DAMAGE. 321541Srgrimes * 331541Srgrimes * @(#)kern_ktrace.c 8.2 (Berkeley) 9/23/93 3450477Speter * $FreeBSD: head/sys/kern/kern_ktrace.c 104230 2002-09-30 19:19:47Z phk $ 351541Srgrimes */ 361541Srgrimes 3713203Swollman#include "opt_ktrace.h" 38101123Srwatson#include "opt_mac.h" 391541Srgrimes 401541Srgrimes#include <sys/param.h> 412112Swollman#include <sys/systm.h> 4297993Sjhb#include <sys/fcntl.h> 4397993Sjhb#include <sys/jail.h> 4497993Sjhb#include <sys/kernel.h> 4597993Sjhb#include <sys/kthread.h> 4676166Smarkm#include <sys/lock.h> 4776166Smarkm#include <sys/mutex.h> 48101123Srwatson#include <sys/mac.h> 4997993Sjhb#include <sys/malloc.h> 5097993Sjhb#include <sys/namei.h> 511541Srgrimes#include <sys/proc.h> 5297993Sjhb#include <sys/unistd.h> 531541Srgrimes#include <sys/vnode.h> 541541Srgrimes#include <sys/ktrace.h> 5597993Sjhb#include <sys/sema.h> 5674927Sjhb#include <sys/sx.h> 5797993Sjhb#include <sys/sysctl.h> 581541Srgrimes#include <sys/syslog.h> 5997993Sjhb#include <sys/sysproto.h> 601541Srgrimes 6130354Sphkstatic MALLOC_DEFINE(M_KTRACE, "KTRACE", "KTRACE"); 6230309Sphk 6313203Swollman#ifdef KTRACE 6412577Sbde 6597993Sjhb#ifndef KTRACE_REQUEST_POOL 6697993Sjhb#define KTRACE_REQUEST_POOL 100 6797993Sjhb#endif 6812819Sphk 6997993Sjhbstruct ktr_request { 7097993Sjhb struct ktr_header ktr_header; 7197993Sjhb struct ucred *ktr_cred; 7297993Sjhb struct vnode *ktr_vp; 7397993Sjhb union { 7497993Sjhb struct ktr_syscall ktr_syscall; 7597993Sjhb struct ktr_sysret ktr_sysret; 7697993Sjhb struct ktr_genio ktr_genio; 7797993Sjhb struct ktr_psig ktr_psig; 7897993Sjhb struct ktr_csw ktr_csw; 7997993Sjhb } ktr_data; 8097993Sjhb STAILQ_ENTRY(ktr_request) ktr_list; 8197993Sjhb}; 8297993Sjhb 8397993Sjhbstatic int data_lengths[] = { 8497993Sjhb 0, /* none */ 8597993Sjhb offsetof(struct ktr_syscall, ktr_args), /* KTR_SYSCALL */ 8697993Sjhb sizeof(struct ktr_sysret), /* KTR_SYSRET */ 8797993Sjhb 0, /* KTR_NAMEI */ 8897993Sjhb sizeof(struct ktr_genio), /* KTR_GENIO */ 8997993Sjhb sizeof(struct ktr_psig), /* KTR_PSIG */ 9097993Sjhb sizeof(struct ktr_csw), /* KTR_CSW */ 9197993Sjhb 0 /* KTR_USER */ 9297993Sjhb}; 9397993Sjhb 9497993Sjhbstatic STAILQ_HEAD(, ktr_request) ktr_todo; 9597993Sjhbstatic STAILQ_HEAD(, ktr_request) ktr_free; 9697993Sjhb 97103234SjhbSYSCTL_NODE(_kern, OID_AUTO, ktrace, CTLFLAG_RD, 0, "KTRACE options"); 98103234Sjhb 9997993Sjhbstatic uint ktr_requestpool = KTRACE_REQUEST_POOL; 100103234SjhbTUNABLE_INT("kern.ktrace.request_pool", &ktr_requestpool); 10197993Sjhb 102103234Sjhbstatic uint ktr_geniosize = PAGE_SIZE; 103103234SjhbTUNABLE_INT("kern.ktrace.genio_size", &ktr_geniosize); 104103234SjhbSYSCTL_UINT(_kern_ktrace, OID_AUTO, genio_size, CTLFLAG_RW, &ktr_geniosize, 105103234Sjhb 0, "Maximum size of genio event payload"); 106103234Sjhb 10797993Sjhbstatic int print_message = 1; 10897993Sjhbstruct mtx ktrace_mtx; 10997993Sjhbstatic struct sema ktrace_sema; 11097993Sjhb 11197993Sjhbstatic void ktrace_init(void *dummy); 11297993Sjhbstatic int sysctl_kern_ktrace_request_pool(SYSCTL_HANDLER_ARGS); 11397993Sjhbstatic uint ktrace_resize_pool(uint newsize); 11497993Sjhbstatic struct ktr_request *ktr_getrequest(int type); 11597993Sjhbstatic void ktr_submitrequest(struct ktr_request *req); 11697993Sjhbstatic void ktr_freerequest(struct ktr_request *req); 11797993Sjhbstatic void ktr_loop(void *dummy); 11897993Sjhbstatic void ktr_writerequest(struct ktr_request *req); 11997993Sjhbstatic int ktrcanset(struct thread *,struct proc *); 12097993Sjhbstatic int ktrsetchildren(struct thread *,struct proc *,int,int,struct vnode *); 12197993Sjhbstatic int ktrops(struct thread *,struct proc *,int,int,struct vnode *); 12297993Sjhb 12397993Sjhbstatic void 12497993Sjhbktrace_init(void *dummy) 1251541Srgrimes{ 12697993Sjhb struct ktr_request *req; 12797993Sjhb int i; 1281541Srgrimes 12997993Sjhb mtx_init(&ktrace_mtx, "ktrace", NULL, MTX_DEF | MTX_QUIET); 13097993Sjhb sema_init(&ktrace_sema, 0, "ktrace"); 13197993Sjhb STAILQ_INIT(&ktr_todo); 13297993Sjhb STAILQ_INIT(&ktr_free); 13397993Sjhb for (i = 0; i < ktr_requestpool; i++) { 13497993Sjhb req = malloc(sizeof(struct ktr_request), M_KTRACE, M_WAITOK); 13597993Sjhb STAILQ_INSERT_HEAD(&ktr_free, req, ktr_list); 13697993Sjhb } 13797993Sjhb kthread_create(ktr_loop, NULL, NULL, RFHIGHPID, "ktrace"); 1381541Srgrimes} 13997993SjhbSYSINIT(ktrace_init, SI_SUB_KTRACE, SI_ORDER_ANY, ktrace_init, NULL); 1401541Srgrimes 14197993Sjhbstatic int 14297993Sjhbsysctl_kern_ktrace_request_pool(SYSCTL_HANDLER_ARGS) 14397993Sjhb{ 14497993Sjhb struct thread *td; 14597993Sjhb uint newsize, oldsize, wantsize; 14697993Sjhb int error; 14797993Sjhb 14897993Sjhb /* Handle easy read-only case first to avoid warnings from GCC. */ 14997993Sjhb if (!req->newptr) { 15097993Sjhb mtx_lock(&ktrace_mtx); 15197993Sjhb oldsize = ktr_requestpool; 15297993Sjhb mtx_unlock(&ktrace_mtx); 15397993Sjhb return (SYSCTL_OUT(req, &oldsize, sizeof(uint))); 15497993Sjhb } 15597993Sjhb 15697993Sjhb error = SYSCTL_IN(req, &wantsize, sizeof(uint)); 15797993Sjhb if (error) 15897993Sjhb return (error); 15997993Sjhb td = curthread; 16097993Sjhb td->td_inktrace = 1; 16197993Sjhb mtx_lock(&ktrace_mtx); 16297993Sjhb oldsize = ktr_requestpool; 16397993Sjhb newsize = ktrace_resize_pool(wantsize); 16497993Sjhb mtx_unlock(&ktrace_mtx); 16597993Sjhb td->td_inktrace = 0; 16697993Sjhb error = SYSCTL_OUT(req, &oldsize, sizeof(uint)); 16797993Sjhb if (error) 16897993Sjhb return (error); 16997993Sjhb if (newsize != wantsize) 17097993Sjhb return (ENOSPC); 17197993Sjhb return (0); 17297993Sjhb} 173103234SjhbSYSCTL_PROC(_kern_ktrace, OID_AUTO, request_pool, CTLTYPE_UINT|CTLFLAG_RW, 17497993Sjhb &ktr_requestpool, 0, sysctl_kern_ktrace_request_pool, "IU", ""); 17597993Sjhb 17697993Sjhbstatic uint 17797993Sjhbktrace_resize_pool(uint newsize) 17897993Sjhb{ 17997993Sjhb struct ktr_request *req; 18097993Sjhb 18197993Sjhb mtx_assert(&ktrace_mtx, MA_OWNED); 18297993Sjhb print_message = 1; 18397993Sjhb if (newsize == ktr_requestpool) 18497993Sjhb return (newsize); 18597993Sjhb if (newsize < ktr_requestpool) 18697993Sjhb /* Shrink pool down to newsize if possible. */ 18797993Sjhb while (ktr_requestpool > newsize) { 18897993Sjhb req = STAILQ_FIRST(&ktr_free); 18997993Sjhb if (req == NULL) 19097993Sjhb return (ktr_requestpool); 19197993Sjhb STAILQ_REMOVE_HEAD(&ktr_free, ktr_list); 19297993Sjhb ktr_requestpool--; 19397993Sjhb mtx_unlock(&ktrace_mtx); 19497993Sjhb free(req, M_KTRACE); 19597993Sjhb mtx_lock(&ktrace_mtx); 19697993Sjhb } 19797993Sjhb else 19897993Sjhb /* Grow pool up to newsize. */ 19997993Sjhb while (ktr_requestpool < newsize) { 20097993Sjhb mtx_unlock(&ktrace_mtx); 20197993Sjhb req = malloc(sizeof(struct ktr_request), M_KTRACE, 20297993Sjhb M_WAITOK); 20397993Sjhb mtx_lock(&ktrace_mtx); 20497993Sjhb STAILQ_INSERT_HEAD(&ktr_free, req, ktr_list); 20597993Sjhb ktr_requestpool++; 20697993Sjhb } 20797993Sjhb return (ktr_requestpool); 20897993Sjhb} 20997993Sjhb 21097993Sjhbstatic struct ktr_request * 21197993Sjhbktr_getrequest(int type) 21297993Sjhb{ 21397993Sjhb struct ktr_request *req; 21497993Sjhb struct thread *td = curthread; 21597993Sjhb struct proc *p = td->td_proc; 21697993Sjhb int pm; 21797993Sjhb 21897993Sjhb td->td_inktrace = 1; 21997993Sjhb mtx_lock(&ktrace_mtx); 22097993Sjhb if (!KTRCHECK(td, type)) { 22197993Sjhb mtx_unlock(&ktrace_mtx); 22297993Sjhb td->td_inktrace = 0; 22397993Sjhb return (NULL); 22497993Sjhb } 22597993Sjhb req = STAILQ_FIRST(&ktr_free); 22697993Sjhb if (req != NULL) { 22797993Sjhb STAILQ_REMOVE_HEAD(&ktr_free, ktr_list); 22897993Sjhb req->ktr_header.ktr_type = type; 22997993Sjhb KASSERT(p->p_tracep != NULL, ("ktrace: no trace vnode")); 23097993Sjhb req->ktr_vp = p->p_tracep; 23197993Sjhb VREF(p->p_tracep); 23297993Sjhb mtx_unlock(&ktrace_mtx); 23397993Sjhb microtime(&req->ktr_header.ktr_time); 23497993Sjhb req->ktr_header.ktr_pid = p->p_pid; 23597993Sjhb bcopy(p->p_comm, req->ktr_header.ktr_comm, MAXCOMLEN + 1); 23697993Sjhb req->ktr_cred = crhold(td->td_ucred); 23797993Sjhb req->ktr_header.ktr_buffer = NULL; 23897993Sjhb req->ktr_header.ktr_len = 0; 23997993Sjhb } else { 24097993Sjhb pm = print_message; 24197993Sjhb print_message = 0; 24297993Sjhb mtx_unlock(&ktrace_mtx); 24397993Sjhb if (pm) 24497993Sjhb printf("Out of ktrace request objects.\n"); 24597993Sjhb td->td_inktrace = 0; 24697993Sjhb } 24797993Sjhb return (req); 24897993Sjhb} 24997993Sjhb 25097993Sjhbstatic void 25197993Sjhbktr_submitrequest(struct ktr_request *req) 25297993Sjhb{ 25397993Sjhb 25497993Sjhb mtx_lock(&ktrace_mtx); 25597993Sjhb STAILQ_INSERT_TAIL(&ktr_todo, req, ktr_list); 25697993Sjhb sema_post(&ktrace_sema); 25797993Sjhb mtx_unlock(&ktrace_mtx); 25897993Sjhb curthread->td_inktrace = 0; 25997993Sjhb} 26097993Sjhb 26197993Sjhbstatic void 26297993Sjhbktr_freerequest(struct ktr_request *req) 26397993Sjhb{ 26497993Sjhb 26597993Sjhb crfree(req->ktr_cred); 266101153Sjhb if (req->ktr_vp != NULL) { 267101153Sjhb mtx_lock(&Giant); 268101153Sjhb vrele(req->ktr_vp); 269101153Sjhb mtx_unlock(&Giant); 270101153Sjhb } 271103235Sjhb if (req->ktr_header.ktr_buffer != NULL) 272103235Sjhb free(req->ktr_header.ktr_buffer, M_KTRACE); 27397993Sjhb mtx_lock(&ktrace_mtx); 27497993Sjhb STAILQ_INSERT_HEAD(&ktr_free, req, ktr_list); 27597993Sjhb mtx_unlock(&ktrace_mtx); 27697993Sjhb} 27797993Sjhb 27897993Sjhbstatic void 27997993Sjhbktr_loop(void *dummy) 28097993Sjhb{ 28197993Sjhb struct ktr_request *req; 28297993Sjhb struct thread *td; 28397993Sjhb struct ucred *cred; 28497993Sjhb 28597993Sjhb /* Only cache these values once. */ 28697993Sjhb td = curthread; 28797993Sjhb cred = td->td_ucred; 28897993Sjhb for (;;) { 28997993Sjhb sema_wait(&ktrace_sema); 29097993Sjhb mtx_lock(&ktrace_mtx); 29197993Sjhb req = STAILQ_FIRST(&ktr_todo); 29297993Sjhb STAILQ_REMOVE_HEAD(&ktr_todo, ktr_list); 29397993Sjhb KASSERT(req != NULL, ("got a NULL request")); 294103236Sjhb mtx_unlock(&ktrace_mtx); 295103236Sjhb /* 296103236Sjhb * It is not enough just to pass the cached cred 297103236Sjhb * to the VOP's in ktr_writerequest(). Some VFS 298103236Sjhb * operations use curthread->td_ucred, so we need 299103236Sjhb * to modify our thread's credentials as well. 300103236Sjhb * Evil. 301103236Sjhb */ 302103236Sjhb td->td_ucred = req->ktr_cred; 303103236Sjhb ktr_writerequest(req); 304103236Sjhb td->td_ucred = cred; 30597993Sjhb ktr_freerequest(req); 30697993Sjhb } 30797993Sjhb} 30897993Sjhb 30982585Sdillon/* 31082585Sdillon * MPSAFE 31182585Sdillon */ 3121549Srgrimesvoid 31397993Sjhbktrsyscall(code, narg, args) 31447955Sdt int code, narg; 31547955Sdt register_t args[]; 3161541Srgrimes{ 31797993Sjhb struct ktr_request *req; 31897993Sjhb struct ktr_syscall *ktp; 31997993Sjhb size_t buflen; 320103233Sjhb char *buf = NULL; 3211541Srgrimes 322103233Sjhb buflen = sizeof(register_t) * narg; 323103233Sjhb if (buflen > 0) { 324103233Sjhb buf = malloc(buflen, M_KTRACE, M_WAITOK); 325103233Sjhb bcopy(args, buf, buflen); 326103233Sjhb } 32797993Sjhb req = ktr_getrequest(KTR_SYSCALL); 328104230Sphk if (req == NULL) { 329104230Sphk if (buf != NULL) 330104230Sphk free(buf, M_KTRACE); 33197993Sjhb return; 332104230Sphk } 33397993Sjhb ktp = &req->ktr_data.ktr_syscall; 3341541Srgrimes ktp->ktr_code = code; 3351541Srgrimes ktp->ktr_narg = narg; 33697993Sjhb if (buflen > 0) { 33797993Sjhb req->ktr_header.ktr_len = buflen; 338103233Sjhb req->ktr_header.ktr_buffer = buf; 33997993Sjhb } 34097993Sjhb ktr_submitrequest(req); 3411541Srgrimes} 3421541Srgrimes 34382585Sdillon/* 34482585Sdillon * MPSAFE 34582585Sdillon */ 3461549Srgrimesvoid 34797993Sjhbktrsysret(code, error, retval) 34847955Sdt int code, error; 34947955Sdt register_t retval; 3501541Srgrimes{ 35197993Sjhb struct ktr_request *req; 35297993Sjhb struct ktr_sysret *ktp; 3531541Srgrimes 35497993Sjhb req = ktr_getrequest(KTR_SYSRET); 35597993Sjhb if (req == NULL) 35697993Sjhb return; 35797993Sjhb ktp = &req->ktr_data.ktr_sysret; 35897993Sjhb ktp->ktr_code = code; 35997993Sjhb ktp->ktr_error = error; 36097993Sjhb ktp->ktr_retval = retval; /* what about val2 ? */ 36197993Sjhb ktr_submitrequest(req); 3621541Srgrimes} 3631541Srgrimes 3641549Srgrimesvoid 36597993Sjhbktrnamei(path) 3661541Srgrimes char *path; 3671541Srgrimes{ 36897993Sjhb struct ktr_request *req; 36997993Sjhb int namelen; 370103233Sjhb char *buf = NULL; 3711541Srgrimes 372103233Sjhb namelen = strlen(path); 373103233Sjhb if (namelen > 0) { 374103233Sjhb buf = malloc(namelen, M_KTRACE, M_WAITOK); 375103233Sjhb bcopy(path, buf, namelen); 376103233Sjhb } 37797993Sjhb req = ktr_getrequest(KTR_NAMEI); 378104230Sphk if (req == NULL) { 379104230Sphk if (buf != NULL) 380104230Sphk free(buf, M_KTRACE); 38197993Sjhb return; 382104230Sphk } 38397993Sjhb if (namelen > 0) { 38497993Sjhb req->ktr_header.ktr_len = namelen; 385103233Sjhb req->ktr_header.ktr_buffer = buf; 38697993Sjhb } 38797993Sjhb ktr_submitrequest(req); 3881541Srgrimes} 3891541Srgrimes 39097993Sjhb/* 39197993Sjhb * Since the uio may not stay valid, we can not hand off this request to 39297993Sjhb * the thread and need to process it synchronously. However, we wish to 39397993Sjhb * keep the relative order of records in a trace file correct, so we 39497993Sjhb * do put this request on the queue (if it isn't empty) and then block. 39597993Sjhb * The ktrace thread waks us back up when it is time for this event to 39697993Sjhb * be posted and blocks until we have completed writing out the event 39797993Sjhb * and woken it back up. 39897993Sjhb */ 3991549Srgrimesvoid 40097993Sjhbktrgenio(fd, rw, uio, error) 4011541Srgrimes int fd; 4021541Srgrimes enum uio_rw rw; 40362378Sgreen struct uio *uio; 40462378Sgreen int error; 4051541Srgrimes{ 40697993Sjhb struct ktr_request *req; 40797993Sjhb struct ktr_genio *ktg; 408103235Sjhb int datalen; 409103235Sjhb char *buf; 4108876Srgrimes 4111541Srgrimes if (error) 4121541Srgrimes return; 413103235Sjhb uio->uio_offset = 0; 414103235Sjhb uio->uio_rw = UIO_WRITE; 415103235Sjhb datalen = imin(uio->uio_resid, ktr_geniosize); 416103235Sjhb buf = malloc(datalen, M_KTRACE, M_WAITOK); 417103235Sjhb if (uiomove(buf, datalen, uio)) { 418103235Sjhb free(buf, M_KTRACE); 419103235Sjhb return; 420103235Sjhb } 42197993Sjhb req = ktr_getrequest(KTR_GENIO); 422103235Sjhb if (req == NULL) { 423103235Sjhb free(buf, M_KTRACE); 42497993Sjhb return; 425103235Sjhb } 42697993Sjhb ktg = &req->ktr_data.ktr_genio; 42797993Sjhb ktg->ktr_fd = fd; 42897993Sjhb ktg->ktr_rw = rw; 429103235Sjhb req->ktr_header.ktr_len = datalen; 430103235Sjhb req->ktr_header.ktr_buffer = buf; 43197993Sjhb ktr_submitrequest(req); 4321541Srgrimes} 4331541Srgrimes 4341549Srgrimesvoid 43597993Sjhbktrpsig(sig, action, mask, code) 43651941Smarcel int sig; 4371541Srgrimes sig_t action; 43851791Smarcel sigset_t *mask; 43951941Smarcel int code; 4401541Srgrimes{ 44197993Sjhb struct ktr_request *req; 44297993Sjhb struct ktr_psig *kp; 4431541Srgrimes 44497993Sjhb req = ktr_getrequest(KTR_PSIG); 44597993Sjhb if (req == NULL) 44697993Sjhb return; 44797993Sjhb kp = &req->ktr_data.ktr_psig; 44897993Sjhb kp->signo = (char)sig; 44997993Sjhb kp->action = action; 45097993Sjhb kp->mask = *mask; 45197993Sjhb kp->code = code; 45297993Sjhb ktr_submitrequest(req); 4531541Srgrimes} 4541541Srgrimes 4551549Srgrimesvoid 45697993Sjhbktrcsw(out, user) 4571541Srgrimes int out, user; 4581541Srgrimes{ 45997993Sjhb struct ktr_request *req; 46097993Sjhb struct ktr_csw *kc; 4611541Srgrimes 46297993Sjhb req = ktr_getrequest(KTR_CSW); 46397993Sjhb if (req == NULL) 46497993Sjhb return; 46597993Sjhb kc = &req->ktr_data.ktr_csw; 46697993Sjhb kc->out = out; 46797993Sjhb kc->user = user; 46897993Sjhb ktr_submitrequest(req); 4691541Srgrimes} 47013203Swollman#endif 4711541Srgrimes 4721541Srgrimes/* Interface and common routines */ 4731541Srgrimes 4741541Srgrimes/* 4751541Srgrimes * ktrace system call 4761541Srgrimes */ 47712221Sbde#ifndef _SYS_SYSPROTO_H_ 4781541Srgrimesstruct ktrace_args { 4791541Srgrimes char *fname; 4801541Srgrimes int ops; 4811541Srgrimes int facs; 4821541Srgrimes int pid; 4831541Srgrimes}; 48412221Sbde#endif 4851541Srgrimes/* ARGSUSED */ 4861549Srgrimesint 48783366Sjulianktrace(td, uap) 48883366Sjulian struct thread *td; 4891541Srgrimes register struct ktrace_args *uap; 4901541Srgrimes{ 49113203Swollman#ifdef KTRACE 4921541Srgrimes register struct vnode *vp = NULL; 4931541Srgrimes register struct proc *p; 4941541Srgrimes struct pgrp *pg; 4951541Srgrimes int facs = uap->facs & ~KTRFAC_ROOT; 4961541Srgrimes int ops = KTROP(uap->ops); 4971541Srgrimes int descend = uap->ops & KTRFLAG_DESCEND; 4981541Srgrimes int ret = 0; 49962550Smckusick int flags, error = 0; 5001541Srgrimes struct nameidata nd; 5011541Srgrimes 50297993Sjhb td->td_inktrace = 1; 5031541Srgrimes if (ops != KTROP_CLEAR) { 5041541Srgrimes /* 5051541Srgrimes * an operation which requires a file argument. 5061541Srgrimes */ 50783366Sjulian NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, uap->fname, td); 50862550Smckusick flags = FREAD | FWRITE | O_NOFOLLOW; 50962550Smckusick error = vn_open(&nd, &flags, 0); 5103308Sphk if (error) { 51197993Sjhb td->td_inktrace = 0; 5121541Srgrimes return (error); 5131541Srgrimes } 51454655Seivind NDFREE(&nd, NDF_ONLY_PNBUF); 5151541Srgrimes vp = nd.ni_vp; 51683366Sjulian VOP_UNLOCK(vp, 0, td); 5171541Srgrimes if (vp->v_type != VREG) { 51891406Sjhb (void) vn_close(vp, FREAD|FWRITE, td->td_ucred, td); 51997993Sjhb td->td_inktrace = 0; 5201541Srgrimes return (EACCES); 5211541Srgrimes } 5221541Srgrimes } 5231541Srgrimes /* 52485397Sdillon * Clear all uses of the tracefile. 5251541Srgrimes */ 5261541Srgrimes if (ops == KTROP_CLEARFILE) { 52774927Sjhb sx_slock(&allproc_lock); 52853212Sphk LIST_FOREACH(p, &allproc, p_list) { 52994618Sjhb PROC_LOCK(p); 5301541Srgrimes if (p->p_tracep == vp) { 53197993Sjhb if (ktrcanset(td, p)) { 53297993Sjhb mtx_lock(&ktrace_mtx); 5331541Srgrimes p->p_tracep = NULL; 5341541Srgrimes p->p_traceflag = 0; 53597993Sjhb mtx_unlock(&ktrace_mtx); 53694618Sjhb PROC_UNLOCK(p); 5371541Srgrimes (void) vn_close(vp, FREAD|FWRITE, 53891406Sjhb td->td_ucred, td); 53985397Sdillon } else { 54094618Sjhb PROC_UNLOCK(p); 5411541Srgrimes error = EPERM; 54285397Sdillon } 54394618Sjhb } else 54494618Sjhb PROC_UNLOCK(p); 5451541Srgrimes } 54674927Sjhb sx_sunlock(&allproc_lock); 5471541Srgrimes goto done; 5481541Srgrimes } 5491541Srgrimes /* 5501541Srgrimes * need something to (un)trace (XXX - why is this here?) 5511541Srgrimes */ 5521541Srgrimes if (!facs) { 5531541Srgrimes error = EINVAL; 5541541Srgrimes goto done; 5551541Srgrimes } 5568876Srgrimes /* 5571541Srgrimes * do it 5581541Srgrimes */ 5591541Srgrimes if (uap->pid < 0) { 5601541Srgrimes /* 5611541Srgrimes * by process group 5621541Srgrimes */ 56394861Sjhb sx_slock(&proctree_lock); 5641541Srgrimes pg = pgfind(-uap->pid); 5651541Srgrimes if (pg == NULL) { 56694861Sjhb sx_sunlock(&proctree_lock); 5671541Srgrimes error = ESRCH; 5681541Srgrimes goto done; 5691541Srgrimes } 57091140Stanimura /* 57191140Stanimura * ktrops() may call vrele(). Lock pg_members 57294861Sjhb * by the proctree_lock rather than pg_mtx. 57391140Stanimura */ 57491140Stanimura PGRP_UNLOCK(pg); 57553212Sphk LIST_FOREACH(p, &pg->pg_members, p_pglist) 5761541Srgrimes if (descend) 57794618Sjhb ret |= ktrsetchildren(td, p, ops, facs, vp); 5788876Srgrimes else 57994618Sjhb ret |= ktrops(td, p, ops, facs, vp); 58094861Sjhb sx_sunlock(&proctree_lock); 5811541Srgrimes } else { 5821541Srgrimes /* 5831541Srgrimes * by pid 5841541Srgrimes */ 5851541Srgrimes p = pfind(uap->pid); 5861541Srgrimes if (p == NULL) { 5871541Srgrimes error = ESRCH; 5881541Srgrimes goto done; 5891541Srgrimes } 59075893Sjhb PROC_UNLOCK(p); 59194618Sjhb /* XXX: UNLOCK above has a race */ 5921541Srgrimes if (descend) 59394618Sjhb ret |= ktrsetchildren(td, p, ops, facs, vp); 5941541Srgrimes else 59594618Sjhb ret |= ktrops(td, p, ops, facs, vp); 5961541Srgrimes } 5971541Srgrimes if (!ret) 5981541Srgrimes error = EPERM; 5991541Srgrimesdone: 6001541Srgrimes if (vp != NULL) 60191406Sjhb (void) vn_close(vp, FWRITE, td->td_ucred, td); 60297993Sjhb td->td_inktrace = 0; 6031541Srgrimes return (error); 60413203Swollman#else 60513203Swollman return ENOSYS; 60613203Swollman#endif 6071541Srgrimes} 6081541Srgrimes 60918398Sphk/* 61018398Sphk * utrace system call 61118398Sphk */ 61218398Sphk/* ARGSUSED */ 61318398Sphkint 61483366Sjulianutrace(td, uap) 61583366Sjulian struct thread *td; 61618398Sphk register struct utrace_args *uap; 61718398Sphk{ 61883366Sjulian 61913203Swollman#ifdef KTRACE 62097993Sjhb struct ktr_request *req; 62199009Salfred void *cp; 622103237Sjhb int error; 62318398Sphk 624103237Sjhb if (!KTRPOINT(td, KTR_USER)) 625103237Sjhb return (0); 62670792Salfred if (uap->len > KTR_USER_MAXLEN) 62770707Salfred return (EINVAL); 628103237Sjhb cp = malloc(uap->len, M_KTRACE, M_WAITOK); 629103237Sjhb error = copyin(uap->addr, cp, uap->len); 630104230Sphk if (error) { 631104230Sphk free(cp, M_KTRACE); 632103237Sjhb return (error); 633104230Sphk } 63497993Sjhb req = ktr_getrequest(KTR_USER); 635104230Sphk if (req == NULL) { 636104230Sphk free(cp, M_KTRACE); 63797993Sjhb return (0); 638104230Sphk } 639103237Sjhb req->ktr_header.ktr_buffer = cp; 640103237Sjhb req->ktr_header.ktr_len = uap->len; 641103237Sjhb ktr_submitrequest(req); 64218398Sphk return (0); 64318398Sphk#else 64418398Sphk return (ENOSYS); 64518398Sphk#endif 64618398Sphk} 64718398Sphk 64818398Sphk#ifdef KTRACE 64912819Sphkstatic int 65094618Sjhbktrops(td, p, ops, facs, vp) 65194618Sjhb struct thread *td; 65294618Sjhb struct proc *p; 6531541Srgrimes int ops, facs; 6541541Srgrimes struct vnode *vp; 6551541Srgrimes{ 65697993Sjhb struct vnode *tracevp = NULL; 6571541Srgrimes 65894618Sjhb PROC_LOCK(p); 65994618Sjhb if (!ktrcanset(td, p)) { 66094618Sjhb PROC_UNLOCK(p); 6611541Srgrimes return (0); 66294618Sjhb } 66397993Sjhb mtx_lock(&ktrace_mtx); 6641541Srgrimes if (ops == KTROP_SET) { 6658876Srgrimes if (p->p_tracep != vp) { 6661541Srgrimes /* 66794618Sjhb * if trace file already in use, relinquish below 6681541Srgrimes */ 66997993Sjhb tracevp = p->p_tracep; 67097993Sjhb VREF(vp); 67197993Sjhb p->p_tracep = vp; 6721541Srgrimes } 6731541Srgrimes p->p_traceflag |= facs; 67494618Sjhb if (td->td_ucred->cr_uid == 0) 6751541Srgrimes p->p_traceflag |= KTRFAC_ROOT; 6768876Srgrimes } else { 6771541Srgrimes /* KTROP_CLEAR */ 6781541Srgrimes if (((p->p_traceflag &= ~facs) & KTRFAC_MASK) == 0) { 6791541Srgrimes /* no more tracing */ 6801541Srgrimes p->p_traceflag = 0; 68197993Sjhb tracevp = p->p_tracep; 68294618Sjhb p->p_tracep = NULL; 6831541Srgrimes } 6841541Srgrimes } 68597993Sjhb mtx_unlock(&ktrace_mtx); 68694618Sjhb PROC_UNLOCK(p); 68797993Sjhb if (tracevp != NULL) 68897993Sjhb vrele(tracevp); 6891541Srgrimes 6901541Srgrimes return (1); 6911541Srgrimes} 6921541Srgrimes 69312819Sphkstatic int 69494618Sjhbktrsetchildren(td, top, ops, facs, vp) 69594618Sjhb struct thread *td; 69694618Sjhb struct proc *top; 6971541Srgrimes int ops, facs; 6981541Srgrimes struct vnode *vp; 6991541Srgrimes{ 7001541Srgrimes register struct proc *p; 7011541Srgrimes register int ret = 0; 7021541Srgrimes 7031541Srgrimes p = top; 70474927Sjhb sx_slock(&proctree_lock); 7051541Srgrimes for (;;) { 70694618Sjhb ret |= ktrops(td, p, ops, facs, vp); 7071541Srgrimes /* 7081541Srgrimes * If this process has children, descend to them next, 7091541Srgrimes * otherwise do any siblings, and if done with this level, 7101541Srgrimes * follow back up the tree (but not past top). 7111541Srgrimes */ 71253212Sphk if (!LIST_EMPTY(&p->p_children)) 71353212Sphk p = LIST_FIRST(&p->p_children); 7141541Srgrimes else for (;;) { 71570317Sjake if (p == top) { 71674927Sjhb sx_sunlock(&proctree_lock); 7171541Srgrimes return (ret); 71870317Sjake } 71953212Sphk if (LIST_NEXT(p, p_sibling)) { 72053212Sphk p = LIST_NEXT(p, p_sibling); 7211541Srgrimes break; 7221541Srgrimes } 72314529Shsu p = p->p_pptr; 7241541Srgrimes } 7251541Srgrimes } 7261541Srgrimes /*NOTREACHED*/ 7271541Srgrimes} 7281541Srgrimes 72912819Sphkstatic void 73097993Sjhbktr_writerequest(struct ktr_request *req) 73197993Sjhb{ 73297993Sjhb struct ktr_header *kth; 7331541Srgrimes struct vnode *vp; 73497993Sjhb struct proc *p; 73597993Sjhb struct thread *td; 73697993Sjhb struct ucred *cred; 7371541Srgrimes struct uio auio; 73897993Sjhb struct iovec aiov[3]; 73962976Smckusick struct mount *mp; 74097993Sjhb int datalen, buflen, vrele_count; 7411541Srgrimes int error; 7421541Srgrimes 74397993Sjhb vp = req->ktr_vp; 74497993Sjhb /* 74597993Sjhb * If vp is NULL, the vp has been cleared out from under this 74697993Sjhb * request, so just drop it. 74797993Sjhb */ 7481541Srgrimes if (vp == NULL) 7491541Srgrimes return; 75097993Sjhb kth = &req->ktr_header; 75197993Sjhb datalen = data_lengths[kth->ktr_type]; 75297993Sjhb buflen = kth->ktr_len; 75397993Sjhb cred = req->ktr_cred; 75497993Sjhb td = curthread; 7551541Srgrimes auio.uio_iov = &aiov[0]; 7561541Srgrimes auio.uio_offset = 0; 7571541Srgrimes auio.uio_segflg = UIO_SYSSPACE; 7581541Srgrimes auio.uio_rw = UIO_WRITE; 7591541Srgrimes aiov[0].iov_base = (caddr_t)kth; 7601541Srgrimes aiov[0].iov_len = sizeof(struct ktr_header); 7611541Srgrimes auio.uio_resid = sizeof(struct ktr_header); 7621541Srgrimes auio.uio_iovcnt = 1; 76397993Sjhb auio.uio_td = td; 76497993Sjhb if (datalen != 0) { 76597993Sjhb aiov[1].iov_base = (caddr_t)&req->ktr_data; 76697993Sjhb aiov[1].iov_len = datalen; 76797993Sjhb auio.uio_resid += datalen; 7681541Srgrimes auio.uio_iovcnt++; 76997993Sjhb kth->ktr_len += datalen; 7701541Srgrimes } 77197993Sjhb if (buflen != 0) { 77297993Sjhb KASSERT(kth->ktr_buffer != NULL, ("ktrace: nothing to write")); 77397993Sjhb aiov[auio.uio_iovcnt].iov_base = kth->ktr_buffer; 77497993Sjhb aiov[auio.uio_iovcnt].iov_len = buflen; 77597993Sjhb auio.uio_resid += buflen; 77697993Sjhb auio.uio_iovcnt++; 777103235Sjhb } 77897993Sjhb mtx_lock(&Giant); 77962976Smckusick vn_start_write(vp, &mp, V_WAIT); 78083366Sjulian vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); 78197993Sjhb (void)VOP_LEASE(vp, td, cred, LEASE_WRITE); 782101123Srwatson#ifdef MAC 783102129Srwatson error = mac_check_vnode_write(cred, NOCRED, vp); 784101123Srwatson if (error == 0) 785101123Srwatson#endif 786101123Srwatson error = VOP_WRITE(vp, &auio, IO_UNIT | IO_APPEND, cred); 78783366Sjulian VOP_UNLOCK(vp, 0, td); 78862976Smckusick vn_finished_write(mp); 78997993Sjhb mtx_unlock(&Giant); 7901541Srgrimes if (!error) 7911541Srgrimes return; 7921541Srgrimes /* 79397993Sjhb * If error encountered, give up tracing on this vnode. We defer 79497993Sjhb * all the vrele()'s on the vnode until after we are finished walking 79597993Sjhb * the various lists to avoid needlessly holding locks. 7961541Srgrimes */ 7971541Srgrimes log(LOG_NOTICE, "ktrace write failed, errno %d, tracing stopped\n", 7981541Srgrimes error); 79997993Sjhb vrele_count = 0; 80097993Sjhb /* 80197993Sjhb * First, clear this vnode from being used by any processes in the 80297993Sjhb * system. 80397993Sjhb * XXX - If one process gets an EPERM writing to the vnode, should 80497993Sjhb * we really do this? Other processes might have suitable 80597993Sjhb * credentials for the operation. 80697993Sjhb */ 80774927Sjhb sx_slock(&allproc_lock); 80853212Sphk LIST_FOREACH(p, &allproc, p_list) { 80997993Sjhb PROC_LOCK(p); 8101541Srgrimes if (p->p_tracep == vp) { 81197993Sjhb mtx_lock(&ktrace_mtx); 8121541Srgrimes p->p_tracep = NULL; 8131541Srgrimes p->p_traceflag = 0; 81497993Sjhb mtx_unlock(&ktrace_mtx); 81597993Sjhb vrele_count++; 8161541Srgrimes } 81797993Sjhb PROC_UNLOCK(p); 8181541Srgrimes } 81974927Sjhb sx_sunlock(&allproc_lock); 82097993Sjhb /* 82197993Sjhb * Second, clear this vnode from any pending requests. 82297993Sjhb */ 82397993Sjhb mtx_lock(&ktrace_mtx); 82497993Sjhb STAILQ_FOREACH(req, &ktr_todo, ktr_list) { 82597993Sjhb if (req->ktr_vp == vp) { 82697993Sjhb req->ktr_vp = NULL; 82797993Sjhb vrele_count++; 82897993Sjhb } 82997993Sjhb } 83097993Sjhb mtx_unlock(&ktrace_mtx); 83197993Sjhb mtx_lock(&Giant); 83297993Sjhb while (vrele_count-- > 0) 83397993Sjhb vrele(vp); 83497993Sjhb mtx_unlock(&Giant); 8351541Srgrimes} 8361541Srgrimes 8371541Srgrimes/* 8381541Srgrimes * Return true if caller has permission to set the ktracing state 8391541Srgrimes * of target. Essentially, the target can't possess any 8401541Srgrimes * more permissions than the caller. KTRFAC_ROOT signifies that 8418876Srgrimes * root previously set the tracing status on the target process, and 8421541Srgrimes * so, only root may further change it. 8431541Srgrimes */ 84412819Sphkstatic int 84594618Sjhbktrcanset(td, targetp) 84694618Sjhb struct thread *td; 84794618Sjhb struct proc *targetp; 8481541Srgrimes{ 8491541Srgrimes 85094618Sjhb PROC_LOCK_ASSERT(targetp, MA_OWNED); 85179335Srwatson if (targetp->p_traceflag & KTRFAC_ROOT && 85294618Sjhb suser_cred(td->td_ucred, PRISON_ROOT)) 85346155Sphk return (0); 8541541Srgrimes 85596886Sjhb if (p_candebug(td, targetp) != 0) 85679335Srwatson return (0); 85779335Srwatson 85879335Srwatson return (1); 8591541Srgrimes} 8601541Srgrimes 86113203Swollman#endif /* KTRACE */ 862