kern_ktrace.c revision 166073
1139804Simp/*- 21541Srgrimes * Copyright (c) 1989, 1993 3152376Srwatson * The Regents of the University of California. 4152376Srwatson * Copyright (c) 2005 Robert N. M. Watson 5152376Srwatson * All rights reserved. 61541Srgrimes * 71541Srgrimes * Redistribution and use in source and binary forms, with or without 81541Srgrimes * modification, are permitted provided that the following conditions 91541Srgrimes * are met: 101541Srgrimes * 1. Redistributions of source code must retain the above copyright 111541Srgrimes * notice, this list of conditions and the following disclaimer. 121541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 131541Srgrimes * notice, this list of conditions and the following disclaimer in the 141541Srgrimes * documentation and/or other materials provided with the distribution. 151541Srgrimes * 4. Neither the name of the University nor the names of its contributors 161541Srgrimes * may be used to endorse or promote products derived from this software 171541Srgrimes * without specific prior written permission. 181541Srgrimes * 191541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 201541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 211541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 221541Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 231541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 241541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 251541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 261541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 271541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 281541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 291541Srgrimes * SUCH DAMAGE. 301541Srgrimes * 311541Srgrimes * @(#)kern_ktrace.c 8.2 (Berkeley) 9/23/93 321541Srgrimes */ 331541Srgrimes 34116182Sobrien#include <sys/cdefs.h> 35116182Sobrien__FBSDID("$FreeBSD: head/sys/kern/kern_ktrace.c 166073 2007-01-17 14:58:53Z delphij $"); 36116182Sobrien 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/kernel.h> 4497993Sjhb#include <sys/kthread.h> 4576166Smarkm#include <sys/lock.h> 4676166Smarkm#include <sys/mutex.h> 4797993Sjhb#include <sys/malloc.h> 48155031Sjeff#include <sys/mount.h> 4997993Sjhb#include <sys/namei.h> 50164033Srwatson#include <sys/priv.h> 511541Srgrimes#include <sys/proc.h> 5297993Sjhb#include <sys/unistd.h> 531541Srgrimes#include <sys/vnode.h> 541541Srgrimes#include <sys/ktrace.h> 5574927Sjhb#include <sys/sx.h> 5697993Sjhb#include <sys/sysctl.h> 571541Srgrimes#include <sys/syslog.h> 5897993Sjhb#include <sys/sysproto.h> 591541Srgrimes 60163606Srwatson#include <security/mac/mac_framework.h> 61163606Srwatson 62152376Srwatson/* 63152376Srwatson * The ktrace facility allows the tracing of certain key events in user space 64152376Srwatson * processes, such as system calls, signal delivery, context switches, and 65152376Srwatson * user generated events using utrace(2). It works by streaming event 66152376Srwatson * records and data to a vnode associated with the process using the 67152376Srwatson * ktrace(2) system call. In general, records can be written directly from 68152376Srwatson * the context that generates the event. One important exception to this is 69152376Srwatson * during a context switch, where sleeping is not permitted. To handle this 70152376Srwatson * case, trace events are generated using in-kernel ktr_request records, and 71152376Srwatson * then delivered to disk at a convenient moment -- either immediately, the 72152376Srwatson * next traceable event, at system call return, or at process exit. 73152376Srwatson * 74152376Srwatson * When dealing with multiple threads or processes writing to the same event 75152376Srwatson * log, ordering guarantees are weak: specifically, if an event has multiple 76152376Srwatson * records (i.e., system call enter and return), they may be interlaced with 77152376Srwatson * records from another event. Process and thread ID information is provided 78152376Srwatson * in the record, and user applications can de-interlace events if required. 79152376Srwatson */ 80152376Srwatson 8130354Sphkstatic MALLOC_DEFINE(M_KTRACE, "KTRACE", "KTRACE"); 8230309Sphk 8313203Swollman#ifdef KTRACE 8412577Sbde 8597993Sjhb#ifndef KTRACE_REQUEST_POOL 8697993Sjhb#define KTRACE_REQUEST_POOL 100 8797993Sjhb#endif 8812819Sphk 8997993Sjhbstruct ktr_request { 9097993Sjhb struct ktr_header ktr_header; 91151927Srwatson void *ktr_buffer; 9297993Sjhb union { 9397993Sjhb struct ktr_syscall ktr_syscall; 9497993Sjhb struct ktr_sysret ktr_sysret; 9597993Sjhb struct ktr_genio ktr_genio; 9697993Sjhb struct ktr_psig ktr_psig; 9797993Sjhb struct ktr_csw ktr_csw; 9897993Sjhb } ktr_data; 9997993Sjhb STAILQ_ENTRY(ktr_request) ktr_list; 10097993Sjhb}; 10197993Sjhb 10297993Sjhbstatic int data_lengths[] = { 10397993Sjhb 0, /* none */ 10497993Sjhb offsetof(struct ktr_syscall, ktr_args), /* KTR_SYSCALL */ 10597993Sjhb sizeof(struct ktr_sysret), /* KTR_SYSRET */ 10697993Sjhb 0, /* KTR_NAMEI */ 10797993Sjhb sizeof(struct ktr_genio), /* KTR_GENIO */ 10897993Sjhb sizeof(struct ktr_psig), /* KTR_PSIG */ 10997993Sjhb sizeof(struct ktr_csw), /* KTR_CSW */ 11097993Sjhb 0 /* KTR_USER */ 11197993Sjhb}; 11297993Sjhb 11397993Sjhbstatic STAILQ_HEAD(, ktr_request) ktr_free; 11497993Sjhb 115141633Sphkstatic SYSCTL_NODE(_kern, OID_AUTO, ktrace, CTLFLAG_RD, 0, "KTRACE options"); 116103234Sjhb 117118607Sjhbstatic u_int ktr_requestpool = KTRACE_REQUEST_POOL; 118103234SjhbTUNABLE_INT("kern.ktrace.request_pool", &ktr_requestpool); 11997993Sjhb 120118607Sjhbstatic u_int ktr_geniosize = PAGE_SIZE; 121103234SjhbTUNABLE_INT("kern.ktrace.genio_size", &ktr_geniosize); 122103234SjhbSYSCTL_UINT(_kern_ktrace, OID_AUTO, genio_size, CTLFLAG_RW, &ktr_geniosize, 123103234Sjhb 0, "Maximum size of genio event payload"); 124103234Sjhb 12597993Sjhbstatic int print_message = 1; 12697993Sjhbstruct mtx ktrace_mtx; 127152376Srwatsonstatic struct sx ktrace_sx; 12897993Sjhb 12997993Sjhbstatic void ktrace_init(void *dummy); 13097993Sjhbstatic int sysctl_kern_ktrace_request_pool(SYSCTL_HANDLER_ARGS); 131118607Sjhbstatic u_int ktrace_resize_pool(u_int newsize); 13297993Sjhbstatic struct ktr_request *ktr_getrequest(int type); 133152376Srwatsonstatic void ktr_submitrequest(struct thread *td, struct ktr_request *req); 13497993Sjhbstatic void ktr_freerequest(struct ktr_request *req); 135152376Srwatsonstatic void ktr_writerequest(struct thread *td, struct ktr_request *req); 13697993Sjhbstatic int ktrcanset(struct thread *,struct proc *); 13797993Sjhbstatic int ktrsetchildren(struct thread *,struct proc *,int,int,struct vnode *); 13897993Sjhbstatic int ktrops(struct thread *,struct proc *,int,int,struct vnode *); 13997993Sjhb 140152376Srwatson/* 141152376Srwatson * ktrace itself generates events, such as context switches, which we do not 142152376Srwatson * wish to trace. Maintain a flag, TDP_INKTRACE, on each thread to determine 143152376Srwatson * whether or not it is in a region where tracing of events should be 144152376Srwatson * suppressed. 145152376Srwatson */ 14697993Sjhbstatic void 147152376Srwatsonktrace_enter(struct thread *td) 148152376Srwatson{ 149152376Srwatson 150152376Srwatson KASSERT(!(td->td_pflags & TDP_INKTRACE), ("ktrace_enter: flag set")); 151152376Srwatson td->td_pflags |= TDP_INKTRACE; 152152376Srwatson} 153152376Srwatson 154152376Srwatsonstatic void 155152376Srwatsonktrace_exit(struct thread *td) 156152376Srwatson{ 157152376Srwatson 158152376Srwatson KASSERT(td->td_pflags & TDP_INKTRACE, ("ktrace_exit: flag not set")); 159152376Srwatson td->td_pflags &= ~TDP_INKTRACE; 160152376Srwatson} 161152376Srwatson 162152376Srwatsonstatic void 163152376Srwatsonktrace_assert(struct thread *td) 164152376Srwatson{ 165152376Srwatson 166152376Srwatson KASSERT(td->td_pflags & TDP_INKTRACE, ("ktrace_assert: flag not set")); 167152376Srwatson} 168152376Srwatson 169152376Srwatsonstatic void 17097993Sjhbktrace_init(void *dummy) 1711541Srgrimes{ 17297993Sjhb struct ktr_request *req; 17397993Sjhb int i; 1741541Srgrimes 17597993Sjhb mtx_init(&ktrace_mtx, "ktrace", NULL, MTX_DEF | MTX_QUIET); 176152376Srwatson sx_init(&ktrace_sx, "ktrace_sx"); 17797993Sjhb STAILQ_INIT(&ktr_free); 17897993Sjhb for (i = 0; i < ktr_requestpool; i++) { 179111119Simp req = malloc(sizeof(struct ktr_request), M_KTRACE, M_WAITOK); 18097993Sjhb STAILQ_INSERT_HEAD(&ktr_free, req, ktr_list); 18197993Sjhb } 1821541Srgrimes} 18397993SjhbSYSINIT(ktrace_init, SI_SUB_KTRACE, SI_ORDER_ANY, ktrace_init, NULL); 1841541Srgrimes 18597993Sjhbstatic int 18697993Sjhbsysctl_kern_ktrace_request_pool(SYSCTL_HANDLER_ARGS) 18797993Sjhb{ 18897993Sjhb struct thread *td; 189118607Sjhb u_int newsize, oldsize, wantsize; 19097993Sjhb int error; 19197993Sjhb 19297993Sjhb /* Handle easy read-only case first to avoid warnings from GCC. */ 19397993Sjhb if (!req->newptr) { 19497993Sjhb mtx_lock(&ktrace_mtx); 19597993Sjhb oldsize = ktr_requestpool; 19697993Sjhb mtx_unlock(&ktrace_mtx); 197118607Sjhb return (SYSCTL_OUT(req, &oldsize, sizeof(u_int))); 19897993Sjhb } 19997993Sjhb 200118607Sjhb error = SYSCTL_IN(req, &wantsize, sizeof(u_int)); 20197993Sjhb if (error) 20297993Sjhb return (error); 20397993Sjhb td = curthread; 204152376Srwatson ktrace_enter(td); 20597993Sjhb mtx_lock(&ktrace_mtx); 20697993Sjhb oldsize = ktr_requestpool; 20797993Sjhb newsize = ktrace_resize_pool(wantsize); 20897993Sjhb mtx_unlock(&ktrace_mtx); 209152376Srwatson ktrace_exit(td); 210118607Sjhb error = SYSCTL_OUT(req, &oldsize, sizeof(u_int)); 21197993Sjhb if (error) 21297993Sjhb return (error); 213122478Sjkoshy if (wantsize > oldsize && newsize < wantsize) 21497993Sjhb return (ENOSPC); 21597993Sjhb return (0); 21697993Sjhb} 217103234SjhbSYSCTL_PROC(_kern_ktrace, OID_AUTO, request_pool, CTLTYPE_UINT|CTLFLAG_RW, 21897993Sjhb &ktr_requestpool, 0, sysctl_kern_ktrace_request_pool, "IU", ""); 21997993Sjhb 220118607Sjhbstatic u_int 221118607Sjhbktrace_resize_pool(u_int newsize) 22297993Sjhb{ 22397993Sjhb struct ktr_request *req; 224122478Sjkoshy int bound; 22597993Sjhb 22697993Sjhb mtx_assert(&ktrace_mtx, MA_OWNED); 22797993Sjhb print_message = 1; 228122478Sjkoshy bound = newsize - ktr_requestpool; 229122478Sjkoshy if (bound == 0) 230122478Sjkoshy return (ktr_requestpool); 231122478Sjkoshy if (bound < 0) 23297993Sjhb /* Shrink pool down to newsize if possible. */ 233122478Sjkoshy while (bound++ < 0) { 23497993Sjhb req = STAILQ_FIRST(&ktr_free); 23597993Sjhb if (req == NULL) 23697993Sjhb return (ktr_requestpool); 23797993Sjhb STAILQ_REMOVE_HEAD(&ktr_free, ktr_list); 23897993Sjhb ktr_requestpool--; 23997993Sjhb mtx_unlock(&ktrace_mtx); 24097993Sjhb free(req, M_KTRACE); 24197993Sjhb mtx_lock(&ktrace_mtx); 24297993Sjhb } 24397993Sjhb else 24497993Sjhb /* Grow pool up to newsize. */ 245122478Sjkoshy while (bound-- > 0) { 24697993Sjhb mtx_unlock(&ktrace_mtx); 24797993Sjhb req = malloc(sizeof(struct ktr_request), M_KTRACE, 248111119Simp M_WAITOK); 24997993Sjhb mtx_lock(&ktrace_mtx); 25097993Sjhb STAILQ_INSERT_HEAD(&ktr_free, req, ktr_list); 25197993Sjhb ktr_requestpool++; 25297993Sjhb } 25397993Sjhb return (ktr_requestpool); 25497993Sjhb} 25597993Sjhb 25697993Sjhbstatic struct ktr_request * 25797993Sjhbktr_getrequest(int type) 25897993Sjhb{ 25997993Sjhb struct ktr_request *req; 26097993Sjhb struct thread *td = curthread; 26197993Sjhb struct proc *p = td->td_proc; 26297993Sjhb int pm; 26397993Sjhb 264152376Srwatson ktrace_enter(td); /* XXX: In caller instead? */ 265152430Srwatson mtx_lock(&ktrace_mtx); 26697993Sjhb if (!KTRCHECK(td, type)) { 267152430Srwatson mtx_unlock(&ktrace_mtx); 268152376Srwatson ktrace_exit(td); 26997993Sjhb return (NULL); 27097993Sjhb } 27197993Sjhb req = STAILQ_FIRST(&ktr_free); 27297993Sjhb if (req != NULL) { 27397993Sjhb STAILQ_REMOVE_HEAD(&ktr_free, ktr_list); 27497993Sjhb req->ktr_header.ktr_type = type; 275112199Sjhb if (p->p_traceflag & KTRFAC_DROP) { 276112199Sjhb req->ktr_header.ktr_type |= KTR_DROP; 277112199Sjhb p->p_traceflag &= ~KTRFAC_DROP; 278112199Sjhb } 279152430Srwatson mtx_unlock(&ktrace_mtx); 28097993Sjhb microtime(&req->ktr_header.ktr_time); 28197993Sjhb req->ktr_header.ktr_pid = p->p_pid; 282151929Srwatson req->ktr_header.ktr_tid = td->td_tid; 28397993Sjhb bcopy(p->p_comm, req->ktr_header.ktr_comm, MAXCOMLEN + 1); 284151927Srwatson req->ktr_buffer = NULL; 28597993Sjhb req->ktr_header.ktr_len = 0; 28697993Sjhb } else { 287112199Sjhb p->p_traceflag |= KTRFAC_DROP; 28897993Sjhb pm = print_message; 28997993Sjhb print_message = 0; 29097993Sjhb mtx_unlock(&ktrace_mtx); 29197993Sjhb if (pm) 29297993Sjhb printf("Out of ktrace request objects.\n"); 293152376Srwatson ktrace_exit(td); 29497993Sjhb } 29597993Sjhb return (req); 29697993Sjhb} 29797993Sjhb 298152376Srwatson/* 299152376Srwatson * Some trace generation environments don't permit direct access to VFS, 300152376Srwatson * such as during a context switch where sleeping is not allowed. Under these 301152376Srwatson * circumstances, queue a request to the thread to be written asynchronously 302152376Srwatson * later. 303152376Srwatson */ 30497993Sjhbstatic void 305152376Srwatsonktr_enqueuerequest(struct thread *td, struct ktr_request *req) 30697993Sjhb{ 30797993Sjhb 30897993Sjhb mtx_lock(&ktrace_mtx); 309152376Srwatson STAILQ_INSERT_TAIL(&td->td_proc->p_ktr, req, ktr_list); 310118599Sjhb mtx_unlock(&ktrace_mtx); 311152376Srwatson ktrace_exit(td); 31297993Sjhb} 31397993Sjhb 314152376Srwatson/* 315152376Srwatson * Drain any pending ktrace records from the per-thread queue to disk. This 316152376Srwatson * is used both internally before committing other records, and also on 317152376Srwatson * system call return. We drain all the ones we can find at the time when 318152376Srwatson * drain is requested, but don't keep draining after that as those events 319152376Srwatson * may me approximately "after" the current event. 320152376Srwatson */ 32197993Sjhbstatic void 322152376Srwatsonktr_drain(struct thread *td) 323152376Srwatson{ 324152376Srwatson struct ktr_request *queued_req; 325152376Srwatson STAILQ_HEAD(, ktr_request) local_queue; 326152376Srwatson 327152376Srwatson ktrace_assert(td); 328152376Srwatson sx_assert(&ktrace_sx, SX_XLOCKED); 329152376Srwatson 330152376Srwatson STAILQ_INIT(&local_queue); /* XXXRW: needed? */ 331152376Srwatson 332152376Srwatson if (!STAILQ_EMPTY(&td->td_proc->p_ktr)) { 333152376Srwatson mtx_lock(&ktrace_mtx); 334152376Srwatson STAILQ_CONCAT(&local_queue, &td->td_proc->p_ktr); 335152376Srwatson mtx_unlock(&ktrace_mtx); 336152376Srwatson 337152376Srwatson while ((queued_req = STAILQ_FIRST(&local_queue))) { 338152376Srwatson STAILQ_REMOVE_HEAD(&local_queue, ktr_list); 339152376Srwatson ktr_writerequest(td, queued_req); 340152376Srwatson ktr_freerequest(queued_req); 341152376Srwatson } 342152376Srwatson } 343152376Srwatson} 344152376Srwatson 345152376Srwatson/* 346152376Srwatson * Submit a trace record for immediate commit to disk -- to be used only 347152376Srwatson * where entering VFS is OK. First drain any pending records that may have 348152376Srwatson * been cached in the thread. 349152376Srwatson */ 350152376Srwatsonstatic void 351152376Srwatsonktr_submitrequest(struct thread *td, struct ktr_request *req) 352152376Srwatson{ 353152376Srwatson 354152376Srwatson ktrace_assert(td); 355152376Srwatson 356152376Srwatson sx_xlock(&ktrace_sx); 357152376Srwatson ktr_drain(td); 358152376Srwatson ktr_writerequest(td, req); 359152376Srwatson ktr_freerequest(req); 360152376Srwatson sx_xunlock(&ktrace_sx); 361152376Srwatson 362152376Srwatson ktrace_exit(td); 363152376Srwatson} 364152376Srwatson 365152376Srwatsonstatic void 36697993Sjhbktr_freerequest(struct ktr_request *req) 36797993Sjhb{ 36897993Sjhb 369151927Srwatson if (req->ktr_buffer != NULL) 370151927Srwatson free(req->ktr_buffer, M_KTRACE); 37197993Sjhb mtx_lock(&ktrace_mtx); 37297993Sjhb STAILQ_INSERT_HEAD(&ktr_free, req, ktr_list); 37397993Sjhb mtx_unlock(&ktrace_mtx); 37497993Sjhb} 37597993Sjhb 37682585Sdillon/* 37782585Sdillon * MPSAFE 37882585Sdillon */ 3791549Srgrimesvoid 38097993Sjhbktrsyscall(code, narg, args) 38147955Sdt int code, narg; 38247955Sdt register_t args[]; 3831541Srgrimes{ 38497993Sjhb struct ktr_request *req; 38597993Sjhb struct ktr_syscall *ktp; 38697993Sjhb size_t buflen; 387103233Sjhb char *buf = NULL; 3881541Srgrimes 389103233Sjhb buflen = sizeof(register_t) * narg; 390103233Sjhb if (buflen > 0) { 391111119Simp buf = malloc(buflen, M_KTRACE, M_WAITOK); 392103233Sjhb bcopy(args, buf, buflen); 393103233Sjhb } 39497993Sjhb req = ktr_getrequest(KTR_SYSCALL); 395104230Sphk if (req == NULL) { 396104230Sphk if (buf != NULL) 397104230Sphk free(buf, M_KTRACE); 39897993Sjhb return; 399104230Sphk } 40097993Sjhb ktp = &req->ktr_data.ktr_syscall; 4011541Srgrimes ktp->ktr_code = code; 4021541Srgrimes ktp->ktr_narg = narg; 40397993Sjhb if (buflen > 0) { 40497993Sjhb req->ktr_header.ktr_len = buflen; 405151927Srwatson req->ktr_buffer = buf; 40697993Sjhb } 407152376Srwatson ktr_submitrequest(curthread, req); 4081541Srgrimes} 4091541Srgrimes 41082585Sdillon/* 41182585Sdillon * MPSAFE 41282585Sdillon */ 4131549Srgrimesvoid 41497993Sjhbktrsysret(code, error, retval) 41547955Sdt int code, error; 41647955Sdt register_t retval; 4171541Srgrimes{ 41897993Sjhb struct ktr_request *req; 41997993Sjhb struct ktr_sysret *ktp; 4201541Srgrimes 42197993Sjhb req = ktr_getrequest(KTR_SYSRET); 42297993Sjhb if (req == NULL) 42397993Sjhb return; 42497993Sjhb ktp = &req->ktr_data.ktr_sysret; 42597993Sjhb ktp->ktr_code = code; 42697993Sjhb ktp->ktr_error = error; 42797993Sjhb ktp->ktr_retval = retval; /* what about val2 ? */ 428152376Srwatson ktr_submitrequest(curthread, req); 4291541Srgrimes} 4301541Srgrimes 431152376Srwatson/* 432152376Srwatson * When a process exits, drain per-process asynchronous trace records. 433152376Srwatson */ 4341549Srgrimesvoid 435152376Srwatsonktrprocexit(struct thread *td) 436152376Srwatson{ 437152376Srwatson 438152376Srwatson ktrace_enter(td); 439152376Srwatson sx_xlock(&ktrace_sx); 440152376Srwatson ktr_drain(td); 441152376Srwatson sx_xunlock(&ktrace_sx); 442152376Srwatson ktrace_exit(td); 443152376Srwatson} 444152376Srwatson 445152376Srwatson/* 446152376Srwatson * When a thread returns, drain any asynchronous records generated by the 447152376Srwatson * system call. 448152376Srwatson */ 449152376Srwatsonvoid 450152376Srwatsonktruserret(struct thread *td) 451152376Srwatson{ 452152376Srwatson 453152376Srwatson ktrace_enter(td); 454152376Srwatson sx_xlock(&ktrace_sx); 455152376Srwatson ktr_drain(td); 456152376Srwatson sx_xunlock(&ktrace_sx); 457152376Srwatson ktrace_exit(td); 458152376Srwatson} 459152376Srwatson 460152376Srwatsonvoid 46197993Sjhbktrnamei(path) 4621541Srgrimes char *path; 4631541Srgrimes{ 46497993Sjhb struct ktr_request *req; 46597993Sjhb int namelen; 466103233Sjhb char *buf = NULL; 4671541Srgrimes 468103233Sjhb namelen = strlen(path); 469103233Sjhb if (namelen > 0) { 470111119Simp buf = malloc(namelen, M_KTRACE, M_WAITOK); 471103233Sjhb bcopy(path, buf, namelen); 472103233Sjhb } 47397993Sjhb req = ktr_getrequest(KTR_NAMEI); 474104230Sphk if (req == NULL) { 475104230Sphk if (buf != NULL) 476104230Sphk free(buf, M_KTRACE); 47797993Sjhb return; 478104230Sphk } 47997993Sjhb if (namelen > 0) { 48097993Sjhb req->ktr_header.ktr_len = namelen; 481151927Srwatson req->ktr_buffer = buf; 48297993Sjhb } 483152376Srwatson ktr_submitrequest(curthread, req); 4841541Srgrimes} 4851541Srgrimes 4861549Srgrimesvoid 48797993Sjhbktrgenio(fd, rw, uio, error) 4881541Srgrimes int fd; 4891541Srgrimes enum uio_rw rw; 49062378Sgreen struct uio *uio; 49162378Sgreen int error; 4921541Srgrimes{ 49397993Sjhb struct ktr_request *req; 49497993Sjhb struct ktr_genio *ktg; 495103235Sjhb int datalen; 496103235Sjhb char *buf; 4978876Srgrimes 498131897Sphk if (error) { 499131897Sphk free(uio, M_IOV); 5001541Srgrimes return; 501131897Sphk } 502103235Sjhb uio->uio_offset = 0; 503103235Sjhb uio->uio_rw = UIO_WRITE; 504103235Sjhb datalen = imin(uio->uio_resid, ktr_geniosize); 505111119Simp buf = malloc(datalen, M_KTRACE, M_WAITOK); 506131897Sphk error = uiomove(buf, datalen, uio); 507131897Sphk free(uio, M_IOV); 508131897Sphk if (error) { 509103235Sjhb free(buf, M_KTRACE); 510103235Sjhb return; 511103235Sjhb } 51297993Sjhb req = ktr_getrequest(KTR_GENIO); 513103235Sjhb if (req == NULL) { 514103235Sjhb free(buf, M_KTRACE); 51597993Sjhb return; 516103235Sjhb } 51797993Sjhb ktg = &req->ktr_data.ktr_genio; 51897993Sjhb ktg->ktr_fd = fd; 51997993Sjhb ktg->ktr_rw = rw; 520103235Sjhb req->ktr_header.ktr_len = datalen; 521151927Srwatson req->ktr_buffer = buf; 522152376Srwatson ktr_submitrequest(curthread, req); 5231541Srgrimes} 5241541Srgrimes 5251549Srgrimesvoid 52697993Sjhbktrpsig(sig, action, mask, code) 52751941Smarcel int sig; 5281541Srgrimes sig_t action; 52951791Smarcel sigset_t *mask; 53051941Smarcel int code; 5311541Srgrimes{ 53297993Sjhb struct ktr_request *req; 53397993Sjhb struct ktr_psig *kp; 5341541Srgrimes 53597993Sjhb req = ktr_getrequest(KTR_PSIG); 53697993Sjhb if (req == NULL) 53797993Sjhb return; 53897993Sjhb kp = &req->ktr_data.ktr_psig; 53997993Sjhb kp->signo = (char)sig; 54097993Sjhb kp->action = action; 54197993Sjhb kp->mask = *mask; 54297993Sjhb kp->code = code; 543152376Srwatson ktr_enqueuerequest(curthread, req); 5441541Srgrimes} 5451541Srgrimes 5461549Srgrimesvoid 54797993Sjhbktrcsw(out, user) 5481541Srgrimes int out, user; 5491541Srgrimes{ 55097993Sjhb struct ktr_request *req; 55197993Sjhb struct ktr_csw *kc; 5521541Srgrimes 55397993Sjhb req = ktr_getrequest(KTR_CSW); 55497993Sjhb if (req == NULL) 55597993Sjhb return; 55697993Sjhb kc = &req->ktr_data.ktr_csw; 55797993Sjhb kc->out = out; 55897993Sjhb kc->user = user; 559152376Srwatson ktr_enqueuerequest(curthread, req); 5601541Srgrimes} 561114026Sjhb#endif /* KTRACE */ 5621541Srgrimes 5631541Srgrimes/* Interface and common routines */ 5641541Srgrimes 5651541Srgrimes/* 5661541Srgrimes * ktrace system call 567114026Sjhb * 568114026Sjhb * MPSAFE 5691541Srgrimes */ 57012221Sbde#ifndef _SYS_SYSPROTO_H_ 5711541Srgrimesstruct ktrace_args { 5721541Srgrimes char *fname; 5731541Srgrimes int ops; 5741541Srgrimes int facs; 5751541Srgrimes int pid; 5761541Srgrimes}; 57712221Sbde#endif 5781541Srgrimes/* ARGSUSED */ 5791549Srgrimesint 58083366Sjulianktrace(td, uap) 58183366Sjulian struct thread *td; 5821541Srgrimes register struct ktrace_args *uap; 5831541Srgrimes{ 58413203Swollman#ifdef KTRACE 5851541Srgrimes register struct vnode *vp = NULL; 5861541Srgrimes register struct proc *p; 5871541Srgrimes struct pgrp *pg; 5881541Srgrimes int facs = uap->facs & ~KTRFAC_ROOT; 5891541Srgrimes int ops = KTROP(uap->ops); 5901541Srgrimes int descend = uap->ops & KTRFLAG_DESCEND; 591147576Spjd int nfound, ret = 0; 592157233Sjhb int flags, error = 0, vfslocked; 5931541Srgrimes struct nameidata nd; 594112198Sjhb struct ucred *cred; 5951541Srgrimes 596114026Sjhb /* 597114026Sjhb * Need something to (un)trace. 598114026Sjhb */ 599114026Sjhb if (ops != KTROP_CLEARFILE && facs == 0) 600114026Sjhb return (EINVAL); 601114026Sjhb 602152376Srwatson ktrace_enter(td); 6031541Srgrimes if (ops != KTROP_CLEAR) { 6041541Srgrimes /* 6051541Srgrimes * an operation which requires a file argument. 6061541Srgrimes */ 607157233Sjhb NDINIT(&nd, LOOKUP, NOFOLLOW | MPSAFE, UIO_USERSPACE, 608157233Sjhb uap->fname, td); 60962550Smckusick flags = FREAD | FWRITE | O_NOFOLLOW; 610118094Sphk error = vn_open(&nd, &flags, 0, -1); 6113308Sphk if (error) { 612152376Srwatson ktrace_exit(td); 6131541Srgrimes return (error); 6141541Srgrimes } 615157233Sjhb vfslocked = NDHASGIANT(&nd); 61654655Seivind NDFREE(&nd, NDF_ONLY_PNBUF); 6171541Srgrimes vp = nd.ni_vp; 61883366Sjulian VOP_UNLOCK(vp, 0, td); 6191541Srgrimes if (vp->v_type != VREG) { 62091406Sjhb (void) vn_close(vp, FREAD|FWRITE, td->td_ucred, td); 621157233Sjhb VFS_UNLOCK_GIANT(vfslocked); 622152376Srwatson ktrace_exit(td); 6231541Srgrimes return (EACCES); 6241541Srgrimes } 625157233Sjhb VFS_UNLOCK_GIANT(vfslocked); 6261541Srgrimes } 6271541Srgrimes /* 62885397Sdillon * Clear all uses of the tracefile. 6291541Srgrimes */ 6301541Srgrimes if (ops == KTROP_CLEARFILE) { 63174927Sjhb sx_slock(&allproc_lock); 632166073Sdelphij FOREACH_PROC_IN_SYSTEM(p) { 63394618Sjhb PROC_LOCK(p); 634112198Sjhb if (p->p_tracevp == vp) { 63597993Sjhb if (ktrcanset(td, p)) { 63697993Sjhb mtx_lock(&ktrace_mtx); 637112198Sjhb cred = p->p_tracecred; 638112198Sjhb p->p_tracecred = NULL; 639112198Sjhb p->p_tracevp = NULL; 6401541Srgrimes p->p_traceflag = 0; 64197993Sjhb mtx_unlock(&ktrace_mtx); 64294618Sjhb PROC_UNLOCK(p); 643157233Sjhb vfslocked = VFS_LOCK_GIANT(vp->v_mount); 6441541Srgrimes (void) vn_close(vp, FREAD|FWRITE, 645112198Sjhb cred, td); 646157233Sjhb VFS_UNLOCK_GIANT(vfslocked); 647112198Sjhb crfree(cred); 64885397Sdillon } else { 64994618Sjhb PROC_UNLOCK(p); 6501541Srgrimes error = EPERM; 65185397Sdillon } 65294618Sjhb } else 65394618Sjhb PROC_UNLOCK(p); 6541541Srgrimes } 65574927Sjhb sx_sunlock(&allproc_lock); 6561541Srgrimes goto done; 6571541Srgrimes } 6581541Srgrimes /* 6591541Srgrimes * do it 6601541Srgrimes */ 661114026Sjhb sx_slock(&proctree_lock); 6621541Srgrimes if (uap->pid < 0) { 6631541Srgrimes /* 6641541Srgrimes * by process group 6651541Srgrimes */ 6661541Srgrimes pg = pgfind(-uap->pid); 6671541Srgrimes if (pg == NULL) { 66894861Sjhb sx_sunlock(&proctree_lock); 6691541Srgrimes error = ESRCH; 6701541Srgrimes goto done; 6711541Srgrimes } 67291140Stanimura /* 67391140Stanimura * ktrops() may call vrele(). Lock pg_members 67494861Sjhb * by the proctree_lock rather than pg_mtx. 67591140Stanimura */ 67691140Stanimura PGRP_UNLOCK(pg); 677147576Spjd nfound = 0; 678147576Spjd LIST_FOREACH(p, &pg->pg_members, p_pglist) { 679147576Spjd PROC_LOCK(p); 680147576Spjd if (p_cansee(td, p) != 0) { 681147576Spjd PROC_UNLOCK(p); 682147576Spjd continue; 683147576Spjd } 684147576Spjd PROC_UNLOCK(p); 685147576Spjd nfound++; 6861541Srgrimes if (descend) 68794618Sjhb ret |= ktrsetchildren(td, p, ops, facs, vp); 6888876Srgrimes else 68994618Sjhb ret |= ktrops(td, p, ops, facs, vp); 690147576Spjd } 691147576Spjd if (nfound == 0) { 692147576Spjd sx_sunlock(&proctree_lock); 693147576Spjd error = ESRCH; 694147576Spjd goto done; 695147576Spjd } 6961541Srgrimes } else { 6971541Srgrimes /* 6981541Srgrimes * by pid 6991541Srgrimes */ 7001541Srgrimes p = pfind(uap->pid); 7011541Srgrimes if (p == NULL) { 702114026Sjhb sx_sunlock(&proctree_lock); 7031541Srgrimes error = ESRCH; 7041541Srgrimes goto done; 7051541Srgrimes } 706147183Spjd error = p_cansee(td, p); 707114026Sjhb /* 708114026Sjhb * The slock of the proctree lock will keep this process 709114026Sjhb * from going away, so unlocking the proc here is ok. 710114026Sjhb */ 71175893Sjhb PROC_UNLOCK(p); 712147520Spjd if (error) { 713147520Spjd sx_sunlock(&proctree_lock); 714147183Spjd goto done; 715147520Spjd } 7161541Srgrimes if (descend) 71794618Sjhb ret |= ktrsetchildren(td, p, ops, facs, vp); 7181541Srgrimes else 71994618Sjhb ret |= ktrops(td, p, ops, facs, vp); 7201541Srgrimes } 721114026Sjhb sx_sunlock(&proctree_lock); 7221541Srgrimes if (!ret) 7231541Srgrimes error = EPERM; 7241541Srgrimesdone: 725114026Sjhb if (vp != NULL) { 726157233Sjhb vfslocked = VFS_LOCK_GIANT(vp->v_mount); 72791406Sjhb (void) vn_close(vp, FWRITE, td->td_ucred, td); 728157233Sjhb VFS_UNLOCK_GIANT(vfslocked); 729114026Sjhb } 730152376Srwatson ktrace_exit(td); 7311541Srgrimes return (error); 732114026Sjhb#else /* !KTRACE */ 733114026Sjhb return (ENOSYS); 734114026Sjhb#endif /* KTRACE */ 7351541Srgrimes} 7361541Srgrimes 73718398Sphk/* 73818398Sphk * utrace system call 739114026Sjhb * 740114026Sjhb * MPSAFE 74118398Sphk */ 74218398Sphk/* ARGSUSED */ 74318398Sphkint 74483366Sjulianutrace(td, uap) 74583366Sjulian struct thread *td; 74618398Sphk register struct utrace_args *uap; 74718398Sphk{ 74883366Sjulian 74913203Swollman#ifdef KTRACE 75097993Sjhb struct ktr_request *req; 75199009Salfred void *cp; 752103237Sjhb int error; 75318398Sphk 754103237Sjhb if (!KTRPOINT(td, KTR_USER)) 755103237Sjhb return (0); 75670792Salfred if (uap->len > KTR_USER_MAXLEN) 75770707Salfred return (EINVAL); 758111119Simp cp = malloc(uap->len, M_KTRACE, M_WAITOK); 759103237Sjhb error = copyin(uap->addr, cp, uap->len); 760104230Sphk if (error) { 761104230Sphk free(cp, M_KTRACE); 762103237Sjhb return (error); 763104230Sphk } 76497993Sjhb req = ktr_getrequest(KTR_USER); 765104230Sphk if (req == NULL) { 766104230Sphk free(cp, M_KTRACE); 767122457Sjkoshy return (ENOMEM); 768104230Sphk } 769151927Srwatson req->ktr_buffer = cp; 770103237Sjhb req->ktr_header.ktr_len = uap->len; 771152376Srwatson ktr_submitrequest(td, req); 77218398Sphk return (0); 773114026Sjhb#else /* !KTRACE */ 77418398Sphk return (ENOSYS); 775114026Sjhb#endif /* KTRACE */ 77618398Sphk} 77718398Sphk 77818398Sphk#ifdef KTRACE 77912819Sphkstatic int 78094618Sjhbktrops(td, p, ops, facs, vp) 78194618Sjhb struct thread *td; 78294618Sjhb struct proc *p; 7831541Srgrimes int ops, facs; 7841541Srgrimes struct vnode *vp; 7851541Srgrimes{ 78697993Sjhb struct vnode *tracevp = NULL; 787112198Sjhb struct ucred *tracecred = NULL; 7881541Srgrimes 78994618Sjhb PROC_LOCK(p); 79094618Sjhb if (!ktrcanset(td, p)) { 79194618Sjhb PROC_UNLOCK(p); 7921541Srgrimes return (0); 79394618Sjhb } 79497993Sjhb mtx_lock(&ktrace_mtx); 7951541Srgrimes if (ops == KTROP_SET) { 796112198Sjhb if (p->p_tracevp != vp) { 7971541Srgrimes /* 79894618Sjhb * if trace file already in use, relinquish below 7991541Srgrimes */ 800112198Sjhb tracevp = p->p_tracevp; 80197993Sjhb VREF(vp); 802112198Sjhb p->p_tracevp = vp; 8031541Srgrimes } 804112198Sjhb if (p->p_tracecred != td->td_ucred) { 805112198Sjhb tracecred = p->p_tracecred; 806112198Sjhb p->p_tracecred = crhold(td->td_ucred); 807112198Sjhb } 8081541Srgrimes p->p_traceflag |= facs; 809164033Srwatson if (priv_check_cred(td->td_ucred, PRIV_KTRACE, 810164033Srwatson SUSER_ALLOWJAIL) == 0) 8111541Srgrimes p->p_traceflag |= KTRFAC_ROOT; 8128876Srgrimes } else { 8131541Srgrimes /* KTROP_CLEAR */ 8141541Srgrimes if (((p->p_traceflag &= ~facs) & KTRFAC_MASK) == 0) { 8151541Srgrimes /* no more tracing */ 8161541Srgrimes p->p_traceflag = 0; 817112198Sjhb tracevp = p->p_tracevp; 818112198Sjhb p->p_tracevp = NULL; 819112198Sjhb tracecred = p->p_tracecred; 820112198Sjhb p->p_tracecred = NULL; 8211541Srgrimes } 8221541Srgrimes } 82397993Sjhb mtx_unlock(&ktrace_mtx); 82494618Sjhb PROC_UNLOCK(p); 825114026Sjhb if (tracevp != NULL) { 826155031Sjeff int vfslocked; 827155031Sjeff 828155031Sjeff vfslocked = VFS_LOCK_GIANT(tracevp->v_mount); 82997993Sjhb vrele(tracevp); 830155031Sjeff VFS_UNLOCK_GIANT(vfslocked); 831114026Sjhb } 832112198Sjhb if (tracecred != NULL) 833112198Sjhb crfree(tracecred); 8341541Srgrimes 8351541Srgrimes return (1); 8361541Srgrimes} 8371541Srgrimes 83812819Sphkstatic int 83994618Sjhbktrsetchildren(td, top, ops, facs, vp) 84094618Sjhb struct thread *td; 84194618Sjhb struct proc *top; 8421541Srgrimes int ops, facs; 8431541Srgrimes struct vnode *vp; 8441541Srgrimes{ 8451541Srgrimes register struct proc *p; 8461541Srgrimes register int ret = 0; 8471541Srgrimes 8481541Srgrimes p = top; 849114026Sjhb sx_assert(&proctree_lock, SX_LOCKED); 8501541Srgrimes for (;;) { 85194618Sjhb ret |= ktrops(td, p, ops, facs, vp); 8521541Srgrimes /* 8531541Srgrimes * If this process has children, descend to them next, 8541541Srgrimes * otherwise do any siblings, and if done with this level, 8551541Srgrimes * follow back up the tree (but not past top). 8561541Srgrimes */ 85753212Sphk if (!LIST_EMPTY(&p->p_children)) 85853212Sphk p = LIST_FIRST(&p->p_children); 8591541Srgrimes else for (;;) { 860114026Sjhb if (p == top) 8611541Srgrimes return (ret); 86253212Sphk if (LIST_NEXT(p, p_sibling)) { 86353212Sphk p = LIST_NEXT(p, p_sibling); 8641541Srgrimes break; 8651541Srgrimes } 86614529Shsu p = p->p_pptr; 8671541Srgrimes } 8681541Srgrimes } 8691541Srgrimes /*NOTREACHED*/ 8701541Srgrimes} 8711541Srgrimes 87212819Sphkstatic void 873152376Srwatsonktr_writerequest(struct thread *td, struct ktr_request *req) 87497993Sjhb{ 87597993Sjhb struct ktr_header *kth; 8761541Srgrimes struct vnode *vp; 87797993Sjhb struct proc *p; 87897993Sjhb struct ucred *cred; 8791541Srgrimes struct uio auio; 88097993Sjhb struct iovec aiov[3]; 88162976Smckusick struct mount *mp; 88297993Sjhb int datalen, buflen, vrele_count; 883157233Sjhb int error, vfslocked; 8841541Srgrimes 88597993Sjhb /* 886152376Srwatson * We hold the vnode and credential for use in I/O in case ktrace is 887152376Srwatson * disabled on the process as we write out the request. 888152376Srwatson * 889152376Srwatson * XXXRW: This is not ideal: we could end up performing a write after 890152376Srwatson * the vnode has been closed. 891152376Srwatson */ 892152376Srwatson mtx_lock(&ktrace_mtx); 893152376Srwatson vp = td->td_proc->p_tracevp; 894152376Srwatson if (vp != NULL) 895152376Srwatson VREF(vp); 896152376Srwatson cred = td->td_proc->p_tracecred; 897152376Srwatson if (cred != NULL) 898152376Srwatson crhold(cred); 899152376Srwatson mtx_unlock(&ktrace_mtx); 900152376Srwatson 901152376Srwatson /* 90297993Sjhb * If vp is NULL, the vp has been cleared out from under this 903152376Srwatson * request, so just drop it. Make sure the credential and vnode are 904152376Srwatson * in sync: we should have both or neither. 90597993Sjhb */ 906152376Srwatson if (vp == NULL) { 907152376Srwatson KASSERT(cred == NULL, ("ktr_writerequest: cred != NULL")); 9081541Srgrimes return; 909152376Srwatson } 910152376Srwatson KASSERT(cred != NULL, ("ktr_writerequest: cred == NULL")); 911152376Srwatson 91297993Sjhb kth = &req->ktr_header; 913118607Sjhb datalen = data_lengths[(u_short)kth->ktr_type & ~KTR_DROP]; 91497993Sjhb buflen = kth->ktr_len; 9151541Srgrimes auio.uio_iov = &aiov[0]; 9161541Srgrimes auio.uio_offset = 0; 9171541Srgrimes auio.uio_segflg = UIO_SYSSPACE; 9181541Srgrimes auio.uio_rw = UIO_WRITE; 9191541Srgrimes aiov[0].iov_base = (caddr_t)kth; 9201541Srgrimes aiov[0].iov_len = sizeof(struct ktr_header); 9211541Srgrimes auio.uio_resid = sizeof(struct ktr_header); 9221541Srgrimes auio.uio_iovcnt = 1; 92397993Sjhb auio.uio_td = td; 92497993Sjhb if (datalen != 0) { 92597993Sjhb aiov[1].iov_base = (caddr_t)&req->ktr_data; 92697993Sjhb aiov[1].iov_len = datalen; 92797993Sjhb auio.uio_resid += datalen; 9281541Srgrimes auio.uio_iovcnt++; 92997993Sjhb kth->ktr_len += datalen; 9301541Srgrimes } 93197993Sjhb if (buflen != 0) { 932151927Srwatson KASSERT(req->ktr_buffer != NULL, ("ktrace: nothing to write")); 933151927Srwatson aiov[auio.uio_iovcnt].iov_base = req->ktr_buffer; 93497993Sjhb aiov[auio.uio_iovcnt].iov_len = buflen; 93597993Sjhb auio.uio_resid += buflen; 93697993Sjhb auio.uio_iovcnt++; 937103235Sjhb } 938152376Srwatson 939157233Sjhb vfslocked = VFS_LOCK_GIANT(vp->v_mount); 94062976Smckusick vn_start_write(vp, &mp, V_WAIT); 94183366Sjulian vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); 94297993Sjhb (void)VOP_LEASE(vp, td, cred, LEASE_WRITE); 943101123Srwatson#ifdef MAC 944102129Srwatson error = mac_check_vnode_write(cred, NOCRED, vp); 945101123Srwatson if (error == 0) 946101123Srwatson#endif 947101123Srwatson error = VOP_WRITE(vp, &auio, IO_UNIT | IO_APPEND, cred); 94883366Sjulian VOP_UNLOCK(vp, 0, td); 94962976Smckusick vn_finished_write(mp); 950154739Sjhb vrele(vp); 951157233Sjhb VFS_UNLOCK_GIANT(vfslocked); 9521541Srgrimes if (!error) 9531541Srgrimes return; 9541541Srgrimes /* 95597993Sjhb * If error encountered, give up tracing on this vnode. We defer 95697993Sjhb * all the vrele()'s on the vnode until after we are finished walking 95797993Sjhb * the various lists to avoid needlessly holding locks. 9581541Srgrimes */ 9591541Srgrimes log(LOG_NOTICE, "ktrace write failed, errno %d, tracing stopped\n", 9601541Srgrimes error); 96197993Sjhb vrele_count = 0; 96297993Sjhb /* 96397993Sjhb * First, clear this vnode from being used by any processes in the 96497993Sjhb * system. 96597993Sjhb * XXX - If one process gets an EPERM writing to the vnode, should 96697993Sjhb * we really do this? Other processes might have suitable 96797993Sjhb * credentials for the operation. 96897993Sjhb */ 969112198Sjhb cred = NULL; 97074927Sjhb sx_slock(&allproc_lock); 971166073Sdelphij FOREACH_PROC_IN_SYSTEM(p) { 97297993Sjhb PROC_LOCK(p); 973112198Sjhb if (p->p_tracevp == vp) { 97497993Sjhb mtx_lock(&ktrace_mtx); 975112198Sjhb p->p_tracevp = NULL; 9761541Srgrimes p->p_traceflag = 0; 977112198Sjhb cred = p->p_tracecred; 978112198Sjhb p->p_tracecred = NULL; 97997993Sjhb mtx_unlock(&ktrace_mtx); 98097993Sjhb vrele_count++; 9811541Srgrimes } 98297993Sjhb PROC_UNLOCK(p); 983112198Sjhb if (cred != NULL) { 984112198Sjhb crfree(cred); 985112198Sjhb cred = NULL; 986112198Sjhb } 9871541Srgrimes } 98874927Sjhb sx_sunlock(&allproc_lock); 989152376Srwatson 99097993Sjhb /* 991152376Srwatson * We can't clear any pending requests in threads that have cached 992152376Srwatson * them but not yet committed them, as those are per-thread. The 993152376Srwatson * thread will have to clear it itself on system call return. 99497993Sjhb */ 995157233Sjhb vfslocked = VFS_LOCK_GIANT(vp->v_mount); 99697993Sjhb while (vrele_count-- > 0) 99797993Sjhb vrele(vp); 998157233Sjhb VFS_UNLOCK_GIANT(vfslocked); 9991541Srgrimes} 10001541Srgrimes 10011541Srgrimes/* 10021541Srgrimes * Return true if caller has permission to set the ktracing state 10031541Srgrimes * of target. Essentially, the target can't possess any 10041541Srgrimes * more permissions than the caller. KTRFAC_ROOT signifies that 10058876Srgrimes * root previously set the tracing status on the target process, and 10061541Srgrimes * so, only root may further change it. 10071541Srgrimes */ 100812819Sphkstatic int 100994618Sjhbktrcanset(td, targetp) 101094618Sjhb struct thread *td; 101194618Sjhb struct proc *targetp; 10121541Srgrimes{ 10131541Srgrimes 101494618Sjhb PROC_LOCK_ASSERT(targetp, MA_OWNED); 101579335Srwatson if (targetp->p_traceflag & KTRFAC_ROOT && 1016164033Srwatson priv_check_cred(td->td_ucred, PRIV_KTRACE, SUSER_ALLOWJAIL)) 101746155Sphk return (0); 10181541Srgrimes 101996886Sjhb if (p_candebug(td, targetp) != 0) 102079335Srwatson return (0); 102179335Srwatson 102279335Srwatson return (1); 10231541Srgrimes} 10241541Srgrimes 102513203Swollman#endif /* KTRACE */ 1026