kern_ktrace.c revision 225617
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 225617 2011-09-16 13:58:51Z kmacy $");
36116182Sobrien
3713203Swollman#include "opt_ktrace.h"
381541Srgrimes
391541Srgrimes#include <sys/param.h>
402112Swollman#include <sys/systm.h>
4197993Sjhb#include <sys/fcntl.h>
4297993Sjhb#include <sys/kernel.h>
4397993Sjhb#include <sys/kthread.h>
4476166Smarkm#include <sys/lock.h>
4576166Smarkm#include <sys/mutex.h>
4697993Sjhb#include <sys/malloc.h>
47155031Sjeff#include <sys/mount.h>
4897993Sjhb#include <sys/namei.h>
49164033Srwatson#include <sys/priv.h>
501541Srgrimes#include <sys/proc.h>
5197993Sjhb#include <sys/unistd.h>
521541Srgrimes#include <sys/vnode.h>
53176471Sdes#include <sys/socket.h>
54176471Sdes#include <sys/stat.h>
551541Srgrimes#include <sys/ktrace.h>
5674927Sjhb#include <sys/sx.h>
5797993Sjhb#include <sys/sysctl.h>
58219042Sdchagin#include <sys/sysent.h>
591541Srgrimes#include <sys/syslog.h>
6097993Sjhb#include <sys/sysproto.h>
611541Srgrimes
62163606Srwatson#include <security/mac/mac_framework.h>
63163606Srwatson
64152376Srwatson/*
65152376Srwatson * The ktrace facility allows the tracing of certain key events in user space
66152376Srwatson * processes, such as system calls, signal delivery, context switches, and
67152376Srwatson * user generated events using utrace(2).  It works by streaming event
68152376Srwatson * records and data to a vnode associated with the process using the
69152376Srwatson * ktrace(2) system call.  In general, records can be written directly from
70152376Srwatson * the context that generates the event.  One important exception to this is
71152376Srwatson * during a context switch, where sleeping is not permitted.  To handle this
72152376Srwatson * case, trace events are generated using in-kernel ktr_request records, and
73152376Srwatson * then delivered to disk at a convenient moment -- either immediately, the
74152376Srwatson * next traceable event, at system call return, or at process exit.
75152376Srwatson *
76152376Srwatson * When dealing with multiple threads or processes writing to the same event
77152376Srwatson * log, ordering guarantees are weak: specifically, if an event has multiple
78152376Srwatson * records (i.e., system call enter and return), they may be interlaced with
79152376Srwatson * records from another event.  Process and thread ID information is provided
80152376Srwatson * in the record, and user applications can de-interlace events if required.
81152376Srwatson */
82152376Srwatson
8330354Sphkstatic MALLOC_DEFINE(M_KTRACE, "KTRACE", "KTRACE");
8430309Sphk
8513203Swollman#ifdef KTRACE
8612577Sbde
87219028SnetchildFEATURE(ktrace, "Kernel support for system-call tracing");
88219028Snetchild
8997993Sjhb#ifndef KTRACE_REQUEST_POOL
9097993Sjhb#define	KTRACE_REQUEST_POOL	100
9197993Sjhb#endif
9212819Sphk
9397993Sjhbstruct ktr_request {
9497993Sjhb	struct	ktr_header ktr_header;
95151927Srwatson	void	*ktr_buffer;
9697993Sjhb	union {
97219042Sdchagin		struct	ktr_proc_ctor ktr_proc_ctor;
9897993Sjhb		struct	ktr_syscall ktr_syscall;
9997993Sjhb		struct	ktr_sysret ktr_sysret;
10097993Sjhb		struct	ktr_genio ktr_genio;
10197993Sjhb		struct	ktr_psig ktr_psig;
10297993Sjhb		struct	ktr_csw ktr_csw;
10397993Sjhb	} ktr_data;
10497993Sjhb	STAILQ_ENTRY(ktr_request) ktr_list;
10597993Sjhb};
10697993Sjhb
10797993Sjhbstatic int data_lengths[] = {
10897993Sjhb	0,					/* none */
10997993Sjhb	offsetof(struct ktr_syscall, ktr_args),	/* KTR_SYSCALL */
11097993Sjhb	sizeof(struct ktr_sysret),		/* KTR_SYSRET */
11197993Sjhb	0,					/* KTR_NAMEI */
11297993Sjhb	sizeof(struct ktr_genio),		/* KTR_GENIO */
11397993Sjhb	sizeof(struct ktr_psig),		/* KTR_PSIG */
114219312Sdchagin	sizeof(struct ktr_csw),			/* KTR_CSW */
115176471Sdes	0,					/* KTR_USER */
116176471Sdes	0,					/* KTR_STRUCT */
117189707Sjhb	0,					/* KTR_SYSCTL */
118219042Sdchagin	sizeof(struct ktr_proc_ctor),		/* KTR_PROCCTOR */
119219042Sdchagin	0,					/* KTR_PROCDTOR */
12097993Sjhb};
12197993Sjhb
12297993Sjhbstatic STAILQ_HEAD(, ktr_request) ktr_free;
12397993Sjhb
124141633Sphkstatic SYSCTL_NODE(_kern, OID_AUTO, ktrace, CTLFLAG_RD, 0, "KTRACE options");
125103234Sjhb
126118607Sjhbstatic u_int ktr_requestpool = KTRACE_REQUEST_POOL;
127103234SjhbTUNABLE_INT("kern.ktrace.request_pool", &ktr_requestpool);
12897993Sjhb
129118607Sjhbstatic u_int ktr_geniosize = PAGE_SIZE;
130103234SjhbTUNABLE_INT("kern.ktrace.genio_size", &ktr_geniosize);
131103234SjhbSYSCTL_UINT(_kern_ktrace, OID_AUTO, genio_size, CTLFLAG_RW, &ktr_geniosize,
132103234Sjhb    0, "Maximum size of genio event payload");
133103234Sjhb
13497993Sjhbstatic int print_message = 1;
135214158Sjhbstatic struct mtx ktrace_mtx;
136152376Srwatsonstatic struct sx ktrace_sx;
13797993Sjhb
13897993Sjhbstatic void ktrace_init(void *dummy);
13997993Sjhbstatic int sysctl_kern_ktrace_request_pool(SYSCTL_HANDLER_ARGS);
140219041Sdchaginstatic u_int ktrace_resize_pool(u_int oldsize, u_int newsize);
141219311Sdchaginstatic struct ktr_request *ktr_getrequest_entered(struct thread *td, int type);
14297993Sjhbstatic struct ktr_request *ktr_getrequest(int type);
143152376Srwatsonstatic void ktr_submitrequest(struct thread *td, struct ktr_request *req);
144214158Sjhbstatic void ktr_freeproc(struct proc *p, struct ucred **uc,
145214158Sjhb    struct vnode **vp);
14697993Sjhbstatic void ktr_freerequest(struct ktr_request *req);
147214158Sjhbstatic void ktr_freerequest_locked(struct ktr_request *req);
148152376Srwatsonstatic void ktr_writerequest(struct thread *td, struct ktr_request *req);
14997993Sjhbstatic int ktrcanset(struct thread *,struct proc *);
15097993Sjhbstatic int ktrsetchildren(struct thread *,struct proc *,int,int,struct vnode *);
15197993Sjhbstatic int ktrops(struct thread *,struct proc *,int,int,struct vnode *);
152219311Sdchaginstatic void ktrprocctor_entered(struct thread *, struct proc *);
15397993Sjhb
154152376Srwatson/*
155152376Srwatson * ktrace itself generates events, such as context switches, which we do not
156152376Srwatson * wish to trace.  Maintain a flag, TDP_INKTRACE, on each thread to determine
157152376Srwatson * whether or not it is in a region where tracing of events should be
158152376Srwatson * suppressed.
159152376Srwatson */
16097993Sjhbstatic void
161152376Srwatsonktrace_enter(struct thread *td)
162152376Srwatson{
163152376Srwatson
164152376Srwatson	KASSERT(!(td->td_pflags & TDP_INKTRACE), ("ktrace_enter: flag set"));
165152376Srwatson	td->td_pflags |= TDP_INKTRACE;
166152376Srwatson}
167152376Srwatson
168152376Srwatsonstatic void
169152376Srwatsonktrace_exit(struct thread *td)
170152376Srwatson{
171152376Srwatson
172152376Srwatson	KASSERT(td->td_pflags & TDP_INKTRACE, ("ktrace_exit: flag not set"));
173152376Srwatson	td->td_pflags &= ~TDP_INKTRACE;
174152376Srwatson}
175152376Srwatson
176152376Srwatsonstatic void
177152376Srwatsonktrace_assert(struct thread *td)
178152376Srwatson{
179152376Srwatson
180152376Srwatson	KASSERT(td->td_pflags & TDP_INKTRACE, ("ktrace_assert: flag not set"));
181152376Srwatson}
182152376Srwatson
183152376Srwatsonstatic void
18497993Sjhbktrace_init(void *dummy)
1851541Srgrimes{
18697993Sjhb	struct ktr_request *req;
18797993Sjhb	int i;
1881541Srgrimes
18997993Sjhb	mtx_init(&ktrace_mtx, "ktrace", NULL, MTX_DEF | MTX_QUIET);
190152376Srwatson	sx_init(&ktrace_sx, "ktrace_sx");
19197993Sjhb	STAILQ_INIT(&ktr_free);
19297993Sjhb	for (i = 0; i < ktr_requestpool; i++) {
193111119Simp		req = malloc(sizeof(struct ktr_request), M_KTRACE, M_WAITOK);
19497993Sjhb		STAILQ_INSERT_HEAD(&ktr_free, req, ktr_list);
19597993Sjhb	}
1961541Srgrimes}
19797993SjhbSYSINIT(ktrace_init, SI_SUB_KTRACE, SI_ORDER_ANY, ktrace_init, NULL);
1981541Srgrimes
19997993Sjhbstatic int
20097993Sjhbsysctl_kern_ktrace_request_pool(SYSCTL_HANDLER_ARGS)
20197993Sjhb{
20297993Sjhb	struct thread *td;
203118607Sjhb	u_int newsize, oldsize, wantsize;
20497993Sjhb	int error;
20597993Sjhb
20697993Sjhb	/* Handle easy read-only case first to avoid warnings from GCC. */
20797993Sjhb	if (!req->newptr) {
20897993Sjhb		oldsize = ktr_requestpool;
209118607Sjhb		return (SYSCTL_OUT(req, &oldsize, sizeof(u_int)));
21097993Sjhb	}
21197993Sjhb
212118607Sjhb	error = SYSCTL_IN(req, &wantsize, sizeof(u_int));
21397993Sjhb	if (error)
21497993Sjhb		return (error);
21597993Sjhb	td = curthread;
216152376Srwatson	ktrace_enter(td);
21797993Sjhb	oldsize = ktr_requestpool;
218219041Sdchagin	newsize = ktrace_resize_pool(oldsize, wantsize);
219152376Srwatson	ktrace_exit(td);
220118607Sjhb	error = SYSCTL_OUT(req, &oldsize, sizeof(u_int));
22197993Sjhb	if (error)
22297993Sjhb		return (error);
223122478Sjkoshy	if (wantsize > oldsize && newsize < wantsize)
22497993Sjhb		return (ENOSPC);
22597993Sjhb	return (0);
22697993Sjhb}
227103234SjhbSYSCTL_PROC(_kern_ktrace, OID_AUTO, request_pool, CTLTYPE_UINT|CTLFLAG_RW,
228211102Sgavin    &ktr_requestpool, 0, sysctl_kern_ktrace_request_pool, "IU",
229211102Sgavin    "Pool buffer size for ktrace(1)");
23097993Sjhb
231118607Sjhbstatic u_int
232219041Sdchaginktrace_resize_pool(u_int oldsize, u_int newsize)
23397993Sjhb{
234219041Sdchagin	STAILQ_HEAD(, ktr_request) ktr_new;
23597993Sjhb	struct ktr_request *req;
236122478Sjkoshy	int bound;
23797993Sjhb
23897993Sjhb	print_message = 1;
239219041Sdchagin	bound = newsize - oldsize;
240122478Sjkoshy	if (bound == 0)
241122478Sjkoshy		return (ktr_requestpool);
242219041Sdchagin	if (bound < 0) {
243219041Sdchagin		mtx_lock(&ktrace_mtx);
24497993Sjhb		/* Shrink pool down to newsize if possible. */
245122478Sjkoshy		while (bound++ < 0) {
24697993Sjhb			req = STAILQ_FIRST(&ktr_free);
24797993Sjhb			if (req == NULL)
248219041Sdchagin				break;
24997993Sjhb			STAILQ_REMOVE_HEAD(&ktr_free, ktr_list);
25097993Sjhb			ktr_requestpool--;
25197993Sjhb			free(req, M_KTRACE);
25297993Sjhb		}
253219041Sdchagin	} else {
25497993Sjhb		/* Grow pool up to newsize. */
255219041Sdchagin		STAILQ_INIT(&ktr_new);
256122478Sjkoshy		while (bound-- > 0) {
25797993Sjhb			req = malloc(sizeof(struct ktr_request), M_KTRACE,
258111119Simp			    M_WAITOK);
259219041Sdchagin			STAILQ_INSERT_HEAD(&ktr_new, req, ktr_list);
26097993Sjhb		}
261219041Sdchagin		mtx_lock(&ktrace_mtx);
262219041Sdchagin		STAILQ_CONCAT(&ktr_free, &ktr_new);
263219041Sdchagin		ktr_requestpool += (newsize - oldsize);
264219041Sdchagin	}
265219041Sdchagin	mtx_unlock(&ktrace_mtx);
26697993Sjhb	return (ktr_requestpool);
26797993Sjhb}
26897993Sjhb
269198411Sjhb/* ktr_getrequest() assumes that ktr_comm[] is the same size as td_name[]. */
270198411SjhbCTASSERT(sizeof(((struct ktr_header *)NULL)->ktr_comm) ==
271198411Sjhb    (sizeof((struct thread *)NULL)->td_name));
272198411Sjhb
27397993Sjhbstatic struct ktr_request *
274219311Sdchaginktr_getrequest_entered(struct thread *td, int type)
27597993Sjhb{
27697993Sjhb	struct ktr_request *req;
27797993Sjhb	struct proc *p = td->td_proc;
27897993Sjhb	int pm;
27997993Sjhb
280152430Srwatson	mtx_lock(&ktrace_mtx);
28197993Sjhb	if (!KTRCHECK(td, type)) {
282152430Srwatson		mtx_unlock(&ktrace_mtx);
28397993Sjhb		return (NULL);
28497993Sjhb	}
28597993Sjhb	req = STAILQ_FIRST(&ktr_free);
28697993Sjhb	if (req != NULL) {
28797993Sjhb		STAILQ_REMOVE_HEAD(&ktr_free, ktr_list);
28897993Sjhb		req->ktr_header.ktr_type = type;
289112199Sjhb		if (p->p_traceflag & KTRFAC_DROP) {
290112199Sjhb			req->ktr_header.ktr_type |= KTR_DROP;
291112199Sjhb			p->p_traceflag &= ~KTRFAC_DROP;
292112199Sjhb		}
293152430Srwatson		mtx_unlock(&ktrace_mtx);
29497993Sjhb		microtime(&req->ktr_header.ktr_time);
29597993Sjhb		req->ktr_header.ktr_pid = p->p_pid;
296151929Srwatson		req->ktr_header.ktr_tid = td->td_tid;
297198411Sjhb		bcopy(td->td_name, req->ktr_header.ktr_comm,
298198411Sjhb		    sizeof(req->ktr_header.ktr_comm));
299151927Srwatson		req->ktr_buffer = NULL;
30097993Sjhb		req->ktr_header.ktr_len = 0;
30197993Sjhb	} else {
302112199Sjhb		p->p_traceflag |= KTRFAC_DROP;
30397993Sjhb		pm = print_message;
30497993Sjhb		print_message = 0;
30597993Sjhb		mtx_unlock(&ktrace_mtx);
30697993Sjhb		if (pm)
30797993Sjhb			printf("Out of ktrace request objects.\n");
30897993Sjhb	}
30997993Sjhb	return (req);
31097993Sjhb}
31197993Sjhb
312219042Sdchaginstatic struct ktr_request *
313219042Sdchaginktr_getrequest(int type)
314219042Sdchagin{
315219042Sdchagin	struct thread *td = curthread;
316219042Sdchagin	struct ktr_request *req;
317219042Sdchagin
318219042Sdchagin	ktrace_enter(td);
319219311Sdchagin	req = ktr_getrequest_entered(td, type);
320219042Sdchagin	if (req == NULL)
321219042Sdchagin		ktrace_exit(td);
322219042Sdchagin
323219042Sdchagin	return (req);
324219042Sdchagin}
325219042Sdchagin
326152376Srwatson/*
327152376Srwatson * Some trace generation environments don't permit direct access to VFS,
328152376Srwatson * such as during a context switch where sleeping is not allowed.  Under these
329152376Srwatson * circumstances, queue a request to the thread to be written asynchronously
330152376Srwatson * later.
331152376Srwatson */
33297993Sjhbstatic void
333152376Srwatsonktr_enqueuerequest(struct thread *td, struct ktr_request *req)
33497993Sjhb{
33597993Sjhb
33697993Sjhb	mtx_lock(&ktrace_mtx);
337152376Srwatson	STAILQ_INSERT_TAIL(&td->td_proc->p_ktr, req, ktr_list);
338118599Sjhb	mtx_unlock(&ktrace_mtx);
33997993Sjhb}
34097993Sjhb
341152376Srwatson/*
342152376Srwatson * Drain any pending ktrace records from the per-thread queue to disk.  This
343152376Srwatson * is used both internally before committing other records, and also on
344152376Srwatson * system call return.  We drain all the ones we can find at the time when
345152376Srwatson * drain is requested, but don't keep draining after that as those events
346189707Sjhb * may be approximately "after" the current event.
347152376Srwatson */
34897993Sjhbstatic void
349152376Srwatsonktr_drain(struct thread *td)
350152376Srwatson{
351152376Srwatson	struct ktr_request *queued_req;
352152376Srwatson	STAILQ_HEAD(, ktr_request) local_queue;
353152376Srwatson
354152376Srwatson	ktrace_assert(td);
355152376Srwatson	sx_assert(&ktrace_sx, SX_XLOCKED);
356152376Srwatson
357211512Sjhb	STAILQ_INIT(&local_queue);
358152376Srwatson
359152376Srwatson	if (!STAILQ_EMPTY(&td->td_proc->p_ktr)) {
360152376Srwatson		mtx_lock(&ktrace_mtx);
361152376Srwatson		STAILQ_CONCAT(&local_queue, &td->td_proc->p_ktr);
362152376Srwatson		mtx_unlock(&ktrace_mtx);
363152376Srwatson
364152376Srwatson		while ((queued_req = STAILQ_FIRST(&local_queue))) {
365152376Srwatson			STAILQ_REMOVE_HEAD(&local_queue, ktr_list);
366152376Srwatson			ktr_writerequest(td, queued_req);
367152376Srwatson			ktr_freerequest(queued_req);
368152376Srwatson		}
369152376Srwatson	}
370152376Srwatson}
371152376Srwatson
372152376Srwatson/*
373152376Srwatson * Submit a trace record for immediate commit to disk -- to be used only
374152376Srwatson * where entering VFS is OK.  First drain any pending records that may have
375152376Srwatson * been cached in the thread.
376152376Srwatson */
377152376Srwatsonstatic void
378219311Sdchaginktr_submitrequest(struct thread *td, struct ktr_request *req)
379152376Srwatson{
380152376Srwatson
381152376Srwatson	ktrace_assert(td);
382152376Srwatson
383152376Srwatson	sx_xlock(&ktrace_sx);
384152376Srwatson	ktr_drain(td);
385152376Srwatson	ktr_writerequest(td, req);
386152376Srwatson	ktr_freerequest(req);
387152376Srwatson	sx_xunlock(&ktrace_sx);
388152376Srwatson	ktrace_exit(td);
389152376Srwatson}
390152376Srwatson
391152376Srwatsonstatic void
39297993Sjhbktr_freerequest(struct ktr_request *req)
39397993Sjhb{
39497993Sjhb
395214158Sjhb	mtx_lock(&ktrace_mtx);
396214158Sjhb	ktr_freerequest_locked(req);
397214158Sjhb	mtx_unlock(&ktrace_mtx);
398214158Sjhb}
399214158Sjhb
400214158Sjhbstatic void
401214158Sjhbktr_freerequest_locked(struct ktr_request *req)
402214158Sjhb{
403214158Sjhb
404214158Sjhb	mtx_assert(&ktrace_mtx, MA_OWNED);
405151927Srwatson	if (req->ktr_buffer != NULL)
406151927Srwatson		free(req->ktr_buffer, M_KTRACE);
40797993Sjhb	STAILQ_INSERT_HEAD(&ktr_free, req, ktr_list);
40897993Sjhb}
40997993Sjhb
410214158Sjhb/*
411214158Sjhb * Disable tracing for a process and release all associated resources.
412214158Sjhb * The caller is responsible for releasing a reference on the returned
413214158Sjhb * vnode and credentials.
414214158Sjhb */
415214158Sjhbstatic void
416214158Sjhbktr_freeproc(struct proc *p, struct ucred **uc, struct vnode **vp)
417214158Sjhb{
418214158Sjhb	struct ktr_request *req;
419214158Sjhb
420214158Sjhb	PROC_LOCK_ASSERT(p, MA_OWNED);
421214158Sjhb	mtx_assert(&ktrace_mtx, MA_OWNED);
422214158Sjhb	*uc = p->p_tracecred;
423214158Sjhb	p->p_tracecred = NULL;
424214158Sjhb	if (vp != NULL)
425214158Sjhb		*vp = p->p_tracevp;
426214158Sjhb	p->p_tracevp = NULL;
427214158Sjhb	p->p_traceflag = 0;
428214158Sjhb	while ((req = STAILQ_FIRST(&p->p_ktr)) != NULL) {
429214158Sjhb		STAILQ_REMOVE_HEAD(&p->p_ktr, ktr_list);
430214158Sjhb		ktr_freerequest_locked(req);
431214158Sjhb	}
432214158Sjhb}
433214158Sjhb
4341549Srgrimesvoid
43597993Sjhbktrsyscall(code, narg, args)
43647955Sdt	int code, narg;
43747955Sdt	register_t args[];
4381541Srgrimes{
43997993Sjhb	struct ktr_request *req;
44097993Sjhb	struct ktr_syscall *ktp;
44197993Sjhb	size_t buflen;
442103233Sjhb	char *buf = NULL;
4431541Srgrimes
444103233Sjhb	buflen = sizeof(register_t) * narg;
445103233Sjhb	if (buflen > 0) {
446111119Simp		buf = malloc(buflen, M_KTRACE, M_WAITOK);
447103233Sjhb		bcopy(args, buf, buflen);
448103233Sjhb	}
44997993Sjhb	req = ktr_getrequest(KTR_SYSCALL);
450104230Sphk	if (req == NULL) {
451104230Sphk		if (buf != NULL)
452104230Sphk			free(buf, M_KTRACE);
45397993Sjhb		return;
454104230Sphk	}
45597993Sjhb	ktp = &req->ktr_data.ktr_syscall;
4561541Srgrimes	ktp->ktr_code = code;
4571541Srgrimes	ktp->ktr_narg = narg;
45897993Sjhb	if (buflen > 0) {
45997993Sjhb		req->ktr_header.ktr_len = buflen;
460151927Srwatson		req->ktr_buffer = buf;
46197993Sjhb	}
462152376Srwatson	ktr_submitrequest(curthread, req);
4631541Srgrimes}
4641541Srgrimes
4651549Srgrimesvoid
46697993Sjhbktrsysret(code, error, retval)
46747955Sdt	int code, error;
46847955Sdt	register_t retval;
4691541Srgrimes{
47097993Sjhb	struct ktr_request *req;
47197993Sjhb	struct ktr_sysret *ktp;
4721541Srgrimes
47397993Sjhb	req = ktr_getrequest(KTR_SYSRET);
47497993Sjhb	if (req == NULL)
47597993Sjhb		return;
47697993Sjhb	ktp = &req->ktr_data.ktr_sysret;
47797993Sjhb	ktp->ktr_code = code;
47897993Sjhb	ktp->ktr_error = error;
47997993Sjhb	ktp->ktr_retval = retval;		/* what about val2 ? */
480152376Srwatson	ktr_submitrequest(curthread, req);
4811541Srgrimes}
4821541Srgrimes
483152376Srwatson/*
484214158Sjhb * When a setuid process execs, disable tracing.
485214158Sjhb *
486214158Sjhb * XXX: We toss any pending asynchronous records.
487152376Srwatson */
4881549Srgrimesvoid
489214158Sjhbktrprocexec(struct proc *p, struct ucred **uc, struct vnode **vp)
490214158Sjhb{
491214158Sjhb
492214158Sjhb	PROC_LOCK_ASSERT(p, MA_OWNED);
493214158Sjhb	mtx_lock(&ktrace_mtx);
494214158Sjhb	ktr_freeproc(p, uc, vp);
495214158Sjhb	mtx_unlock(&ktrace_mtx);
496214158Sjhb}
497214158Sjhb
498214158Sjhb/*
499214158Sjhb * When a process exits, drain per-process asynchronous trace records
500214158Sjhb * and disable tracing.
501214158Sjhb */
502214158Sjhbvoid
503152376Srwatsonktrprocexit(struct thread *td)
504152376Srwatson{
505219042Sdchagin	struct ktr_request *req;
506214158Sjhb	struct proc *p;
507214158Sjhb	struct ucred *cred;
508214158Sjhb	struct vnode *vp;
509214158Sjhb	int vfslocked;
510152376Srwatson
511214158Sjhb	p = td->td_proc;
512214158Sjhb	if (p->p_traceflag == 0)
513214158Sjhb		return;
514214158Sjhb
515152376Srwatson	ktrace_enter(td);
516219311Sdchagin	req = ktr_getrequest_entered(td, KTR_PROCDTOR);
517219311Sdchagin	if (req != NULL)
518219311Sdchagin		ktr_enqueuerequest(td, req);
519152376Srwatson	sx_xlock(&ktrace_sx);
520152376Srwatson	ktr_drain(td);
521152376Srwatson	sx_xunlock(&ktrace_sx);
522214158Sjhb	PROC_LOCK(p);
523214158Sjhb	mtx_lock(&ktrace_mtx);
524214158Sjhb	ktr_freeproc(p, &cred, &vp);
525214158Sjhb	mtx_unlock(&ktrace_mtx);
526214158Sjhb	PROC_UNLOCK(p);
527214158Sjhb	if (vp != NULL) {
528214158Sjhb		vfslocked = VFS_LOCK_GIANT(vp->v_mount);
529214158Sjhb		vrele(vp);
530214158Sjhb		VFS_UNLOCK_GIANT(vfslocked);
531214158Sjhb	}
532214158Sjhb	if (cred != NULL)
533214158Sjhb		crfree(cred);
534152376Srwatson	ktrace_exit(td);
535152376Srwatson}
536152376Srwatson
537219042Sdchaginstatic void
538219311Sdchaginktrprocctor_entered(struct thread *td, struct proc *p)
539219042Sdchagin{
540219042Sdchagin	struct ktr_proc_ctor *ktp;
541219042Sdchagin	struct ktr_request *req;
542219312Sdchagin	struct thread *td2;
543219042Sdchagin
544219042Sdchagin	ktrace_assert(td);
545219042Sdchagin	td2 = FIRST_THREAD_IN_PROC(p);
546219311Sdchagin	req = ktr_getrequest_entered(td2, KTR_PROCCTOR);
547219042Sdchagin	if (req == NULL)
548219042Sdchagin		return;
549219042Sdchagin	ktp = &req->ktr_data.ktr_proc_ctor;
550219042Sdchagin	ktp->sv_flags = p->p_sysent->sv_flags;
551219311Sdchagin	ktr_enqueuerequest(td2, req);
552219042Sdchagin}
553219042Sdchagin
554219042Sdchaginvoid
555219042Sdchaginktrprocctor(struct proc *p)
556219042Sdchagin{
557219042Sdchagin	struct thread *td = curthread;
558219042Sdchagin
559219042Sdchagin	if ((p->p_traceflag & KTRFAC_MASK) == 0)
560219042Sdchagin		return;
561219042Sdchagin
562219042Sdchagin	ktrace_enter(td);
563219311Sdchagin	ktrprocctor_entered(td, p);
564219042Sdchagin	ktrace_exit(td);
565219042Sdchagin}
566219042Sdchagin
567152376Srwatson/*
568214158Sjhb * When a process forks, enable tracing in the new process if needed.
569214158Sjhb */
570214158Sjhbvoid
571214158Sjhbktrprocfork(struct proc *p1, struct proc *p2)
572214158Sjhb{
573214158Sjhb
574219042Sdchagin	PROC_LOCK(p1);
575214158Sjhb	mtx_lock(&ktrace_mtx);
576214158Sjhb	KASSERT(p2->p_tracevp == NULL, ("new process has a ktrace vnode"));
577214158Sjhb	if (p1->p_traceflag & KTRFAC_INHERIT) {
578214158Sjhb		p2->p_traceflag = p1->p_traceflag;
579214158Sjhb		if ((p2->p_tracevp = p1->p_tracevp) != NULL) {
580214158Sjhb			VREF(p2->p_tracevp);
581214158Sjhb			KASSERT(p1->p_tracecred != NULL,
582214158Sjhb			    ("ktrace vnode with no cred"));
583214158Sjhb			p2->p_tracecred = crhold(p1->p_tracecred);
584214158Sjhb		}
585214158Sjhb	}
586214158Sjhb	mtx_unlock(&ktrace_mtx);
587219042Sdchagin	PROC_UNLOCK(p1);
588219042Sdchagin
589219042Sdchagin	ktrprocctor(p2);
590214158Sjhb}
591214158Sjhb
592214158Sjhb/*
593152376Srwatson * When a thread returns, drain any asynchronous records generated by the
594152376Srwatson * system call.
595152376Srwatson */
596152376Srwatsonvoid
597152376Srwatsonktruserret(struct thread *td)
598152376Srwatson{
599152376Srwatson
600152376Srwatson	ktrace_enter(td);
601152376Srwatson	sx_xlock(&ktrace_sx);
602152376Srwatson	ktr_drain(td);
603152376Srwatson	sx_xunlock(&ktrace_sx);
604152376Srwatson	ktrace_exit(td);
605152376Srwatson}
606152376Srwatson
607152376Srwatsonvoid
60897993Sjhbktrnamei(path)
6091541Srgrimes	char *path;
6101541Srgrimes{
61197993Sjhb	struct ktr_request *req;
61297993Sjhb	int namelen;
613103233Sjhb	char *buf = NULL;
6141541Srgrimes
615103233Sjhb	namelen = strlen(path);
616103233Sjhb	if (namelen > 0) {
617111119Simp		buf = malloc(namelen, M_KTRACE, M_WAITOK);
618103233Sjhb		bcopy(path, buf, namelen);
619103233Sjhb	}
62097993Sjhb	req = ktr_getrequest(KTR_NAMEI);
621104230Sphk	if (req == NULL) {
622104230Sphk		if (buf != NULL)
623104230Sphk			free(buf, M_KTRACE);
62497993Sjhb		return;
625104230Sphk	}
62697993Sjhb	if (namelen > 0) {
62797993Sjhb		req->ktr_header.ktr_len = namelen;
628151927Srwatson		req->ktr_buffer = buf;
62997993Sjhb	}
630152376Srwatson	ktr_submitrequest(curthread, req);
6311541Srgrimes}
6321541Srgrimes
6331549Srgrimesvoid
634189707Sjhbktrsysctl(name, namelen)
635189707Sjhb	int *name;
636189707Sjhb	u_int namelen;
637189707Sjhb{
638189707Sjhb	struct ktr_request *req;
639189707Sjhb	u_int mib[CTL_MAXNAME + 2];
640189707Sjhb	char *mibname;
641189707Sjhb	size_t mibnamelen;
642189707Sjhb	int error;
643189707Sjhb
644189707Sjhb	/* Lookup name of mib. */
645189707Sjhb	KASSERT(namelen <= CTL_MAXNAME, ("sysctl MIB too long"));
646189707Sjhb	mib[0] = 0;
647189707Sjhb	mib[1] = 1;
648189707Sjhb	bcopy(name, mib + 2, namelen * sizeof(*name));
649189707Sjhb	mibnamelen = 128;
650189707Sjhb	mibname = malloc(mibnamelen, M_KTRACE, M_WAITOK);
651189707Sjhb	error = kernel_sysctl(curthread, mib, namelen + 2, mibname, &mibnamelen,
652189707Sjhb	    NULL, 0, &mibnamelen, 0);
653189707Sjhb	if (error) {
654189707Sjhb		free(mibname, M_KTRACE);
655189707Sjhb		return;
656189707Sjhb	}
657189707Sjhb	req = ktr_getrequest(KTR_SYSCTL);
658189707Sjhb	if (req == NULL) {
659189707Sjhb		free(mibname, M_KTRACE);
660189707Sjhb		return;
661189707Sjhb	}
662189707Sjhb	req->ktr_header.ktr_len = mibnamelen;
663189707Sjhb	req->ktr_buffer = mibname;
664189707Sjhb	ktr_submitrequest(curthread, req);
665189707Sjhb}
666189707Sjhb
667189707Sjhbvoid
66897993Sjhbktrgenio(fd, rw, uio, error)
6691541Srgrimes	int fd;
6701541Srgrimes	enum uio_rw rw;
67162378Sgreen	struct uio *uio;
67262378Sgreen	int error;
6731541Srgrimes{
67497993Sjhb	struct ktr_request *req;
67597993Sjhb	struct ktr_genio *ktg;
676103235Sjhb	int datalen;
677103235Sjhb	char *buf;
6788876Srgrimes
679131897Sphk	if (error) {
680131897Sphk		free(uio, M_IOV);
6811541Srgrimes		return;
682131897Sphk	}
683103235Sjhb	uio->uio_offset = 0;
684103235Sjhb	uio->uio_rw = UIO_WRITE;
685103235Sjhb	datalen = imin(uio->uio_resid, ktr_geniosize);
686111119Simp	buf = malloc(datalen, M_KTRACE, M_WAITOK);
687131897Sphk	error = uiomove(buf, datalen, uio);
688131897Sphk	free(uio, M_IOV);
689131897Sphk	if (error) {
690103235Sjhb		free(buf, M_KTRACE);
691103235Sjhb		return;
692103235Sjhb	}
69397993Sjhb	req = ktr_getrequest(KTR_GENIO);
694103235Sjhb	if (req == NULL) {
695103235Sjhb		free(buf, M_KTRACE);
69697993Sjhb		return;
697103235Sjhb	}
69897993Sjhb	ktg = &req->ktr_data.ktr_genio;
69997993Sjhb	ktg->ktr_fd = fd;
70097993Sjhb	ktg->ktr_rw = rw;
701103235Sjhb	req->ktr_header.ktr_len = datalen;
702151927Srwatson	req->ktr_buffer = buf;
703152376Srwatson	ktr_submitrequest(curthread, req);
7041541Srgrimes}
7051541Srgrimes
7061549Srgrimesvoid
70797993Sjhbktrpsig(sig, action, mask, code)
70851941Smarcel	int sig;
7091541Srgrimes	sig_t action;
71051791Smarcel	sigset_t *mask;
71151941Smarcel	int code;
7121541Srgrimes{
713219311Sdchagin	struct thread *td = curthread;
71497993Sjhb	struct ktr_request *req;
71597993Sjhb	struct ktr_psig	*kp;
7161541Srgrimes
71797993Sjhb	req = ktr_getrequest(KTR_PSIG);
71897993Sjhb	if (req == NULL)
71997993Sjhb		return;
72097993Sjhb	kp = &req->ktr_data.ktr_psig;
72197993Sjhb	kp->signo = (char)sig;
72297993Sjhb	kp->action = action;
72397993Sjhb	kp->mask = *mask;
72497993Sjhb	kp->code = code;
725219311Sdchagin	ktr_enqueuerequest(td, req);
726219311Sdchagin	ktrace_exit(td);
7271541Srgrimes}
7281541Srgrimes
7291549Srgrimesvoid
73097993Sjhbktrcsw(out, user)
7311541Srgrimes	int out, user;
7321541Srgrimes{
733219311Sdchagin	struct thread *td = curthread;
73497993Sjhb	struct ktr_request *req;
73597993Sjhb	struct ktr_csw *kc;
7361541Srgrimes
73797993Sjhb	req = ktr_getrequest(KTR_CSW);
73897993Sjhb	if (req == NULL)
73997993Sjhb		return;
74097993Sjhb	kc = &req->ktr_data.ktr_csw;
74197993Sjhb	kc->out = out;
74297993Sjhb	kc->user = user;
743219311Sdchagin	ktr_enqueuerequest(td, req);
744219311Sdchagin	ktrace_exit(td);
7451541Srgrimes}
746176471Sdes
747176471Sdesvoid
748210064Sjhbktrstruct(name, data, datalen)
749176471Sdes	const char *name;
750176471Sdes	void *data;
751176471Sdes	size_t datalen;
752176471Sdes{
753176471Sdes	struct ktr_request *req;
754176471Sdes	char *buf = NULL;
755176471Sdes	size_t buflen;
756176471Sdes
757176471Sdes	if (!data)
758176471Sdes		datalen = 0;
759210064Sjhb	buflen = strlen(name) + 1 + datalen;
760176471Sdes	buf = malloc(buflen, M_KTRACE, M_WAITOK);
761210064Sjhb	strcpy(buf, name);
762210064Sjhb	bcopy(data, buf + strlen(name) + 1, datalen);
763176471Sdes	if ((req = ktr_getrequest(KTR_STRUCT)) == NULL) {
764176471Sdes		free(buf, M_KTRACE);
765176471Sdes		return;
766176471Sdes	}
767176471Sdes	req->ktr_buffer = buf;
768176471Sdes	req->ktr_header.ktr_len = buflen;
769176471Sdes	ktr_submitrequest(curthread, req);
770176471Sdes}
771114026Sjhb#endif /* KTRACE */
7721541Srgrimes
7731541Srgrimes/* Interface and common routines */
7741541Srgrimes
77512221Sbde#ifndef _SYS_SYSPROTO_H_
7761541Srgrimesstruct ktrace_args {
7771541Srgrimes	char	*fname;
7781541Srgrimes	int	ops;
7791541Srgrimes	int	facs;
7801541Srgrimes	int	pid;
7811541Srgrimes};
78212221Sbde#endif
7831541Srgrimes/* ARGSUSED */
7841549Srgrimesint
785225617Skmacysys_ktrace(td, uap)
78683366Sjulian	struct thread *td;
7871541Srgrimes	register struct ktrace_args *uap;
7881541Srgrimes{
78913203Swollman#ifdef KTRACE
7901541Srgrimes	register struct vnode *vp = NULL;
7911541Srgrimes	register struct proc *p;
7921541Srgrimes	struct pgrp *pg;
7931541Srgrimes	int facs = uap->facs & ~KTRFAC_ROOT;
7941541Srgrimes	int ops = KTROP(uap->ops);
7951541Srgrimes	int descend = uap->ops & KTRFLAG_DESCEND;
796147576Spjd	int nfound, ret = 0;
797157233Sjhb	int flags, error = 0, vfslocked;
7981541Srgrimes	struct nameidata nd;
799112198Sjhb	struct ucred *cred;
8001541Srgrimes
801114026Sjhb	/*
802114026Sjhb	 * Need something to (un)trace.
803114026Sjhb	 */
804114026Sjhb	if (ops != KTROP_CLEARFILE && facs == 0)
805114026Sjhb		return (EINVAL);
806114026Sjhb
807152376Srwatson	ktrace_enter(td);
8081541Srgrimes	if (ops != KTROP_CLEAR) {
8091541Srgrimes		/*
8101541Srgrimes		 * an operation which requires a file argument.
8111541Srgrimes		 */
812157233Sjhb		NDINIT(&nd, LOOKUP, NOFOLLOW | MPSAFE, UIO_USERSPACE,
813157233Sjhb		    uap->fname, td);
81462550Smckusick		flags = FREAD | FWRITE | O_NOFOLLOW;
815170152Skib		error = vn_open(&nd, &flags, 0, NULL);
8163308Sphk		if (error) {
817152376Srwatson			ktrace_exit(td);
8181541Srgrimes			return (error);
8191541Srgrimes		}
820157233Sjhb		vfslocked = NDHASGIANT(&nd);
82154655Seivind		NDFREE(&nd, NDF_ONLY_PNBUF);
8221541Srgrimes		vp = nd.ni_vp;
823175294Sattilio		VOP_UNLOCK(vp, 0);
8241541Srgrimes		if (vp->v_type != VREG) {
82591406Sjhb			(void) vn_close(vp, FREAD|FWRITE, td->td_ucred, td);
826157233Sjhb			VFS_UNLOCK_GIANT(vfslocked);
827152376Srwatson			ktrace_exit(td);
8281541Srgrimes			return (EACCES);
8291541Srgrimes		}
830157233Sjhb		VFS_UNLOCK_GIANT(vfslocked);
8311541Srgrimes	}
8321541Srgrimes	/*
83385397Sdillon	 * Clear all uses of the tracefile.
8341541Srgrimes	 */
8351541Srgrimes	if (ops == KTROP_CLEARFILE) {
836166678Smpp		int vrele_count;
837166678Smpp
838166678Smpp		vrele_count = 0;
83974927Sjhb		sx_slock(&allproc_lock);
840166073Sdelphij		FOREACH_PROC_IN_SYSTEM(p) {
84194618Sjhb			PROC_LOCK(p);
842112198Sjhb			if (p->p_tracevp == vp) {
84397993Sjhb				if (ktrcanset(td, p)) {
84497993Sjhb					mtx_lock(&ktrace_mtx);
845214158Sjhb					ktr_freeproc(p, &cred, NULL);
84697993Sjhb					mtx_unlock(&ktrace_mtx);
847166678Smpp					vrele_count++;
848112198Sjhb					crfree(cred);
849166678Smpp				} else
8501541Srgrimes					error = EPERM;
851166678Smpp			}
852166678Smpp			PROC_UNLOCK(p);
8531541Srgrimes		}
85474927Sjhb		sx_sunlock(&allproc_lock);
855166678Smpp		if (vrele_count > 0) {
856166678Smpp			vfslocked = VFS_LOCK_GIANT(vp->v_mount);
857166678Smpp			while (vrele_count-- > 0)
858166678Smpp				vrele(vp);
859166678Smpp			VFS_UNLOCK_GIANT(vfslocked);
860166678Smpp		}
8611541Srgrimes		goto done;
8621541Srgrimes	}
8631541Srgrimes	/*
8641541Srgrimes	 * do it
8651541Srgrimes	 */
866114026Sjhb	sx_slock(&proctree_lock);
8671541Srgrimes	if (uap->pid < 0) {
8681541Srgrimes		/*
8691541Srgrimes		 * by process group
8701541Srgrimes		 */
8711541Srgrimes		pg = pgfind(-uap->pid);
8721541Srgrimes		if (pg == NULL) {
87394861Sjhb			sx_sunlock(&proctree_lock);
8741541Srgrimes			error = ESRCH;
8751541Srgrimes			goto done;
8761541Srgrimes		}
87791140Stanimura		/*
87891140Stanimura		 * ktrops() may call vrele(). Lock pg_members
87994861Sjhb		 * by the proctree_lock rather than pg_mtx.
88091140Stanimura		 */
88191140Stanimura		PGRP_UNLOCK(pg);
882147576Spjd		nfound = 0;
883147576Spjd		LIST_FOREACH(p, &pg->pg_members, p_pglist) {
884147576Spjd			PROC_LOCK(p);
885220390Sjhb			if (p->p_state == PRS_NEW ||
886220390Sjhb			    p_cansee(td, p) != 0) {
887147576Spjd				PROC_UNLOCK(p);
888147576Spjd				continue;
889147576Spjd			}
890147576Spjd			nfound++;
8911541Srgrimes			if (descend)
89294618Sjhb				ret |= ktrsetchildren(td, p, ops, facs, vp);
8938876Srgrimes			else
89494618Sjhb				ret |= ktrops(td, p, ops, facs, vp);
895147576Spjd		}
896147576Spjd		if (nfound == 0) {
897147576Spjd			sx_sunlock(&proctree_lock);
898147576Spjd			error = ESRCH;
899147576Spjd			goto done;
900147576Spjd		}
9011541Srgrimes	} else {
9021541Srgrimes		/*
9031541Srgrimes		 * by pid
9041541Srgrimes		 */
9051541Srgrimes		p = pfind(uap->pid);
906211439Sjhb		if (p == NULL)
9071541Srgrimes			error = ESRCH;
908211439Sjhb		else
909211439Sjhb			error = p_cansee(td, p);
910147520Spjd		if (error) {
911211439Sjhb			if (p != NULL)
912211439Sjhb				PROC_UNLOCK(p);
913147520Spjd			sx_sunlock(&proctree_lock);
914147183Spjd			goto done;
915147520Spjd		}
9161541Srgrimes		if (descend)
91794618Sjhb			ret |= ktrsetchildren(td, p, ops, facs, vp);
9181541Srgrimes		else
91994618Sjhb			ret |= ktrops(td, p, ops, facs, vp);
9201541Srgrimes	}
921114026Sjhb	sx_sunlock(&proctree_lock);
9221541Srgrimes	if (!ret)
9231541Srgrimes		error = EPERM;
9241541Srgrimesdone:
925114026Sjhb	if (vp != NULL) {
926157233Sjhb		vfslocked = VFS_LOCK_GIANT(vp->v_mount);
92791406Sjhb		(void) vn_close(vp, FWRITE, td->td_ucred, td);
928157233Sjhb		VFS_UNLOCK_GIANT(vfslocked);
929114026Sjhb	}
930152376Srwatson	ktrace_exit(td);
9311541Srgrimes	return (error);
932114026Sjhb#else /* !KTRACE */
933114026Sjhb	return (ENOSYS);
934114026Sjhb#endif /* KTRACE */
9351541Srgrimes}
9361541Srgrimes
93718398Sphk/* ARGSUSED */
93818398Sphkint
939225617Skmacysys_utrace(td, uap)
94083366Sjulian	struct thread *td;
94118398Sphk	register struct utrace_args *uap;
94218398Sphk{
94383366Sjulian
94413203Swollman#ifdef KTRACE
94597993Sjhb	struct ktr_request *req;
94699009Salfred	void *cp;
947103237Sjhb	int error;
94818398Sphk
949103237Sjhb	if (!KTRPOINT(td, KTR_USER))
950103237Sjhb		return (0);
95170792Salfred	if (uap->len > KTR_USER_MAXLEN)
95270707Salfred		return (EINVAL);
953111119Simp	cp = malloc(uap->len, M_KTRACE, M_WAITOK);
954103237Sjhb	error = copyin(uap->addr, cp, uap->len);
955104230Sphk	if (error) {
956104230Sphk		free(cp, M_KTRACE);
957103237Sjhb		return (error);
958104230Sphk	}
95997993Sjhb	req = ktr_getrequest(KTR_USER);
960104230Sphk	if (req == NULL) {
961104230Sphk		free(cp, M_KTRACE);
962122457Sjkoshy		return (ENOMEM);
963104230Sphk	}
964151927Srwatson	req->ktr_buffer = cp;
965103237Sjhb	req->ktr_header.ktr_len = uap->len;
966152376Srwatson	ktr_submitrequest(td, req);
96718398Sphk	return (0);
968114026Sjhb#else /* !KTRACE */
96918398Sphk	return (ENOSYS);
970114026Sjhb#endif /* KTRACE */
97118398Sphk}
97218398Sphk
97318398Sphk#ifdef KTRACE
97412819Sphkstatic int
97594618Sjhbktrops(td, p, ops, facs, vp)
97694618Sjhb	struct thread *td;
97794618Sjhb	struct proc *p;
9781541Srgrimes	int ops, facs;
9791541Srgrimes	struct vnode *vp;
9801541Srgrimes{
98197993Sjhb	struct vnode *tracevp = NULL;
982112198Sjhb	struct ucred *tracecred = NULL;
9831541Srgrimes
984211439Sjhb	PROC_LOCK_ASSERT(p, MA_OWNED);
98594618Sjhb	if (!ktrcanset(td, p)) {
98694618Sjhb		PROC_UNLOCK(p);
9871541Srgrimes		return (0);
98894618Sjhb	}
989211439Sjhb	if (p->p_flag & P_WEXIT) {
990211439Sjhb		/* If the process is exiting, just ignore it. */
991211439Sjhb		PROC_UNLOCK(p);
992211439Sjhb		return (1);
993211439Sjhb	}
99497993Sjhb	mtx_lock(&ktrace_mtx);
9951541Srgrimes	if (ops == KTROP_SET) {
996112198Sjhb		if (p->p_tracevp != vp) {
9971541Srgrimes			/*
99894618Sjhb			 * if trace file already in use, relinquish below
9991541Srgrimes			 */
1000112198Sjhb			tracevp = p->p_tracevp;
100197993Sjhb			VREF(vp);
1002112198Sjhb			p->p_tracevp = vp;
10031541Srgrimes		}
1004112198Sjhb		if (p->p_tracecred != td->td_ucred) {
1005112198Sjhb			tracecred = p->p_tracecred;
1006112198Sjhb			p->p_tracecred = crhold(td->td_ucred);
1007112198Sjhb		}
10081541Srgrimes		p->p_traceflag |= facs;
1009170587Srwatson		if (priv_check(td, PRIV_KTRACE) == 0)
10101541Srgrimes			p->p_traceflag |= KTRFAC_ROOT;
10118876Srgrimes	} else {
10121541Srgrimes		/* KTROP_CLEAR */
1013214158Sjhb		if (((p->p_traceflag &= ~facs) & KTRFAC_MASK) == 0)
10141541Srgrimes			/* no more tracing */
1015214158Sjhb			ktr_freeproc(p, &tracecred, &tracevp);
10161541Srgrimes	}
101797993Sjhb	mtx_unlock(&ktrace_mtx);
1018219311Sdchagin	if ((p->p_traceflag & KTRFAC_MASK) != 0)
1019219311Sdchagin		ktrprocctor_entered(td, p);
102094618Sjhb	PROC_UNLOCK(p);
1021114026Sjhb	if (tracevp != NULL) {
1022155031Sjeff		int vfslocked;
1023155031Sjeff
1024155031Sjeff		vfslocked = VFS_LOCK_GIANT(tracevp->v_mount);
102597993Sjhb		vrele(tracevp);
1026155031Sjeff		VFS_UNLOCK_GIANT(vfslocked);
1027114026Sjhb	}
1028112198Sjhb	if (tracecred != NULL)
1029112198Sjhb		crfree(tracecred);
10301541Srgrimes
10311541Srgrimes	return (1);
10321541Srgrimes}
10331541Srgrimes
103412819Sphkstatic int
103594618Sjhbktrsetchildren(td, top, ops, facs, vp)
103694618Sjhb	struct thread *td;
103794618Sjhb	struct proc *top;
10381541Srgrimes	int ops, facs;
10391541Srgrimes	struct vnode *vp;
10401541Srgrimes{
10411541Srgrimes	register struct proc *p;
10421541Srgrimes	register int ret = 0;
10431541Srgrimes
10441541Srgrimes	p = top;
1045211439Sjhb	PROC_LOCK_ASSERT(p, MA_OWNED);
1046114026Sjhb	sx_assert(&proctree_lock, SX_LOCKED);
10471541Srgrimes	for (;;) {
104894618Sjhb		ret |= ktrops(td, p, ops, facs, vp);
10491541Srgrimes		/*
10501541Srgrimes		 * If this process has children, descend to them next,
10511541Srgrimes		 * otherwise do any siblings, and if done with this level,
10521541Srgrimes		 * follow back up the tree (but not past top).
10531541Srgrimes		 */
105453212Sphk		if (!LIST_EMPTY(&p->p_children))
105553212Sphk			p = LIST_FIRST(&p->p_children);
10561541Srgrimes		else for (;;) {
1057114026Sjhb			if (p == top)
10581541Srgrimes				return (ret);
105953212Sphk			if (LIST_NEXT(p, p_sibling)) {
106053212Sphk				p = LIST_NEXT(p, p_sibling);
10611541Srgrimes				break;
10621541Srgrimes			}
106314529Shsu			p = p->p_pptr;
10641541Srgrimes		}
1065211439Sjhb		PROC_LOCK(p);
10661541Srgrimes	}
10671541Srgrimes	/*NOTREACHED*/
10681541Srgrimes}
10691541Srgrimes
107012819Sphkstatic void
1071152376Srwatsonktr_writerequest(struct thread *td, struct ktr_request *req)
107297993Sjhb{
107397993Sjhb	struct ktr_header *kth;
10741541Srgrimes	struct vnode *vp;
107597993Sjhb	struct proc *p;
107697993Sjhb	struct ucred *cred;
10771541Srgrimes	struct uio auio;
107897993Sjhb	struct iovec aiov[3];
107962976Smckusick	struct mount *mp;
108097993Sjhb	int datalen, buflen, vrele_count;
1081157233Sjhb	int error, vfslocked;
10821541Srgrimes
108397993Sjhb	/*
1084152376Srwatson	 * We hold the vnode and credential for use in I/O in case ktrace is
1085152376Srwatson	 * disabled on the process as we write out the request.
1086152376Srwatson	 *
1087152376Srwatson	 * XXXRW: This is not ideal: we could end up performing a write after
1088152376Srwatson	 * the vnode has been closed.
1089152376Srwatson	 */
1090152376Srwatson	mtx_lock(&ktrace_mtx);
1091152376Srwatson	vp = td->td_proc->p_tracevp;
1092152376Srwatson	cred = td->td_proc->p_tracecred;
1093152376Srwatson
1094152376Srwatson	/*
109597993Sjhb	 * If vp is NULL, the vp has been cleared out from under this
1096152376Srwatson	 * request, so just drop it.  Make sure the credential and vnode are
1097152376Srwatson	 * in sync: we should have both or neither.
109897993Sjhb	 */
1099152376Srwatson	if (vp == NULL) {
1100152376Srwatson		KASSERT(cred == NULL, ("ktr_writerequest: cred != NULL"));
1101185583Sbz		mtx_unlock(&ktrace_mtx);
11021541Srgrimes		return;
1103152376Srwatson	}
1104185583Sbz	VREF(vp);
1105152376Srwatson	KASSERT(cred != NULL, ("ktr_writerequest: cred == NULL"));
1106185583Sbz	crhold(cred);
1107185583Sbz	mtx_unlock(&ktrace_mtx);
1108152376Srwatson
110997993Sjhb	kth = &req->ktr_header;
1110189707Sjhb	KASSERT(((u_short)kth->ktr_type & ~KTR_DROP) <
1111189707Sjhb	    sizeof(data_lengths) / sizeof(data_lengths[0]),
1112189707Sjhb	    ("data_lengths array overflow"));
1113118607Sjhb	datalen = data_lengths[(u_short)kth->ktr_type & ~KTR_DROP];
111497993Sjhb	buflen = kth->ktr_len;
11151541Srgrimes	auio.uio_iov = &aiov[0];
11161541Srgrimes	auio.uio_offset = 0;
11171541Srgrimes	auio.uio_segflg = UIO_SYSSPACE;
11181541Srgrimes	auio.uio_rw = UIO_WRITE;
11191541Srgrimes	aiov[0].iov_base = (caddr_t)kth;
11201541Srgrimes	aiov[0].iov_len = sizeof(struct ktr_header);
11211541Srgrimes	auio.uio_resid = sizeof(struct ktr_header);
11221541Srgrimes	auio.uio_iovcnt = 1;
112397993Sjhb	auio.uio_td = td;
112497993Sjhb	if (datalen != 0) {
112597993Sjhb		aiov[1].iov_base = (caddr_t)&req->ktr_data;
112697993Sjhb		aiov[1].iov_len = datalen;
112797993Sjhb		auio.uio_resid += datalen;
11281541Srgrimes		auio.uio_iovcnt++;
112997993Sjhb		kth->ktr_len += datalen;
11301541Srgrimes	}
113197993Sjhb	if (buflen != 0) {
1132151927Srwatson		KASSERT(req->ktr_buffer != NULL, ("ktrace: nothing to write"));
1133151927Srwatson		aiov[auio.uio_iovcnt].iov_base = req->ktr_buffer;
113497993Sjhb		aiov[auio.uio_iovcnt].iov_len = buflen;
113597993Sjhb		auio.uio_resid += buflen;
113697993Sjhb		auio.uio_iovcnt++;
1137103235Sjhb	}
1138152376Srwatson
1139157233Sjhb	vfslocked = VFS_LOCK_GIANT(vp->v_mount);
114062976Smckusick	vn_start_write(vp, &mp, V_WAIT);
1141175202Sattilio	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
1142101123Srwatson#ifdef MAC
1143172930Srwatson	error = mac_vnode_check_write(cred, NOCRED, vp);
1144101123Srwatson	if (error == 0)
1145101123Srwatson#endif
1146101123Srwatson		error = VOP_WRITE(vp, &auio, IO_UNIT | IO_APPEND, cred);
1147175294Sattilio	VOP_UNLOCK(vp, 0);
114862976Smckusick	vn_finished_write(mp);
1149185583Sbz	crfree(cred);
1150185583Sbz	if (!error) {
1151185583Sbz		vrele(vp);
1152185583Sbz		VFS_UNLOCK_GIANT(vfslocked);
1153185583Sbz		return;
1154185583Sbz	}
1155157233Sjhb	VFS_UNLOCK_GIANT(vfslocked);
1156185583Sbz
11571541Srgrimes	/*
115897993Sjhb	 * If error encountered, give up tracing on this vnode.  We defer
115997993Sjhb	 * all the vrele()'s on the vnode until after we are finished walking
116097993Sjhb	 * the various lists to avoid needlessly holding locks.
1161185583Sbz	 * NB: at this point we still hold the vnode reference that must
1162185583Sbz	 * not go away as we need the valid vnode to compare with. Thus let
1163185583Sbz	 * vrele_count start at 1 and the reference will be freed
1164185583Sbz	 * by the loop at the end after our last use of vp.
11651541Srgrimes	 */
11661541Srgrimes	log(LOG_NOTICE, "ktrace write failed, errno %d, tracing stopped\n",
11671541Srgrimes	    error);
1168185583Sbz	vrele_count = 1;
116997993Sjhb	/*
117097993Sjhb	 * First, clear this vnode from being used by any processes in the
117197993Sjhb	 * system.
117297993Sjhb	 * XXX - If one process gets an EPERM writing to the vnode, should
117397993Sjhb	 * we really do this?  Other processes might have suitable
117497993Sjhb	 * credentials for the operation.
117597993Sjhb	 */
1176112198Sjhb	cred = NULL;
117774927Sjhb	sx_slock(&allproc_lock);
1178166073Sdelphij	FOREACH_PROC_IN_SYSTEM(p) {
117997993Sjhb		PROC_LOCK(p);
1180112198Sjhb		if (p->p_tracevp == vp) {
118197993Sjhb			mtx_lock(&ktrace_mtx);
1182214158Sjhb			ktr_freeproc(p, &cred, NULL);
118397993Sjhb			mtx_unlock(&ktrace_mtx);
118497993Sjhb			vrele_count++;
11851541Srgrimes		}
118697993Sjhb		PROC_UNLOCK(p);
1187112198Sjhb		if (cred != NULL) {
1188112198Sjhb			crfree(cred);
1189112198Sjhb			cred = NULL;
1190112198Sjhb		}
11911541Srgrimes	}
119274927Sjhb	sx_sunlock(&allproc_lock);
1193152376Srwatson
1194157233Sjhb	vfslocked = VFS_LOCK_GIANT(vp->v_mount);
119597993Sjhb	while (vrele_count-- > 0)
119697993Sjhb		vrele(vp);
1197157233Sjhb	VFS_UNLOCK_GIANT(vfslocked);
11981541Srgrimes}
11991541Srgrimes
12001541Srgrimes/*
12011541Srgrimes * Return true if caller has permission to set the ktracing state
12021541Srgrimes * of target.  Essentially, the target can't possess any
12031541Srgrimes * more permissions than the caller.  KTRFAC_ROOT signifies that
12048876Srgrimes * root previously set the tracing status on the target process, and
12051541Srgrimes * so, only root may further change it.
12061541Srgrimes */
120712819Sphkstatic int
120894618Sjhbktrcanset(td, targetp)
120994618Sjhb	struct thread *td;
121094618Sjhb	struct proc *targetp;
12111541Srgrimes{
12121541Srgrimes
121394618Sjhb	PROC_LOCK_ASSERT(targetp, MA_OWNED);
121479335Srwatson	if (targetp->p_traceflag & KTRFAC_ROOT &&
1215170587Srwatson	    priv_check(td, PRIV_KTRACE))
121646155Sphk		return (0);
12171541Srgrimes
121896886Sjhb	if (p_candebug(td, targetp) != 0)
121979335Srwatson		return (0);
122079335Srwatson
122179335Srwatson	return (1);
12221541Srgrimes}
12231541Srgrimes
122413203Swollman#endif /* KTRACE */
1225