kern_ktrace.c revision 83366
1/*
2 * Copyright (c) 1989, 1993
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 *    must display the following acknowledgement:
15 *	This product includes software developed by the University of
16 *	California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 *	@(#)kern_ktrace.c	8.2 (Berkeley) 9/23/93
34 * $FreeBSD: head/sys/kern/kern_ktrace.c 83366 2001-09-12 08:38:13Z julian $
35 */
36
37#include "opt_ktrace.h"
38
39#include <sys/param.h>
40#include <sys/systm.h>
41#include <sys/lock.h>
42#include <sys/mutex.h>
43#include <sys/sysproto.h>
44#include <sys/kernel.h>
45#include <sys/proc.h>
46#include <sys/fcntl.h>
47#include <sys/namei.h>
48#include <sys/vnode.h>
49#include <sys/ktrace.h>
50#include <sys/malloc.h>
51#include <sys/sx.h>
52#include <sys/syslog.h>
53#include <sys/jail.h>
54
55static MALLOC_DEFINE(M_KTRACE, "KTRACE", "KTRACE");
56
57#ifdef KTRACE
58static struct ktr_header *ktrgetheader __P((int type));
59static void ktrwrite __P((struct vnode *, struct ktr_header *, struct uio *));
60static int ktrcanset __P((struct proc *,struct proc *));
61static int ktrsetchildren __P((struct proc *,struct proc *,int,int,struct vnode *));
62static int ktrops __P((struct proc *,struct proc *,int,int,struct vnode *));
63
64
65static struct ktr_header *
66ktrgetheader(type)
67	int type;
68{
69	register struct ktr_header *kth;
70	struct proc *p = curproc;	/* XXX */
71
72	MALLOC(kth, struct ktr_header *, sizeof (struct ktr_header),
73		M_KTRACE, M_WAITOK);
74	kth->ktr_type = type;
75	microtime(&kth->ktr_time);
76	kth->ktr_pid = p->p_pid;
77	bcopy(p->p_comm, kth->ktr_comm, MAXCOMLEN + 1);
78	return (kth);
79}
80
81/*
82 * MPSAFE
83 */
84void
85ktrsyscall(vp, code, narg, args)
86	struct vnode *vp;
87	int code, narg;
88	register_t args[];
89{
90	struct	ktr_header *kth;
91	struct	ktr_syscall *ktp;
92	register int len = offsetof(struct ktr_syscall, ktr_args) +
93	    (narg * sizeof(register_t));
94	struct proc *p = curproc;	/* XXX */
95	register_t *argp;
96	int i;
97
98	mtx_lock(&Giant);
99	p->p_traceflag |= KTRFAC_ACTIVE;
100	kth = ktrgetheader(KTR_SYSCALL);
101	MALLOC(ktp, struct ktr_syscall *, len, M_KTRACE, M_WAITOK);
102	ktp->ktr_code = code;
103	ktp->ktr_narg = narg;
104	argp = &ktp->ktr_args[0];
105	for (i = 0; i < narg; i++)
106		*argp++ = args[i];
107	kth->ktr_buffer = (caddr_t)ktp;
108	kth->ktr_len = len;
109	ktrwrite(vp, kth, NULL);
110	FREE(ktp, M_KTRACE);
111	FREE(kth, M_KTRACE);
112	p->p_traceflag &= ~KTRFAC_ACTIVE;
113	mtx_unlock(&Giant);
114}
115
116/*
117 * MPSAFE
118 */
119void
120ktrsysret(vp, code, error, retval)
121	struct vnode *vp;
122	int code, error;
123	register_t retval;
124{
125	struct ktr_header *kth;
126	struct ktr_sysret ktp;
127	struct proc *p = curproc;	/* XXX */
128
129	mtx_lock(&Giant);
130	p->p_traceflag |= KTRFAC_ACTIVE;
131	kth = ktrgetheader(KTR_SYSRET);
132	ktp.ktr_code = code;
133	ktp.ktr_error = error;
134	ktp.ktr_retval = retval;		/* what about val2 ? */
135
136	kth->ktr_buffer = (caddr_t)&ktp;
137	kth->ktr_len = sizeof(struct ktr_sysret);
138
139	ktrwrite(vp, kth, NULL);
140	FREE(kth, M_KTRACE);
141	p->p_traceflag &= ~KTRFAC_ACTIVE;
142	mtx_unlock(&Giant);
143}
144
145void
146ktrnamei(vp, path)
147	struct vnode *vp;
148	char *path;
149{
150	struct ktr_header *kth;
151	struct proc *p = curproc;	/* XXX */
152
153	p->p_traceflag |= KTRFAC_ACTIVE;
154	kth = ktrgetheader(KTR_NAMEI);
155	kth->ktr_len = strlen(path);
156	kth->ktr_buffer = path;
157
158	ktrwrite(vp, kth, NULL);
159	FREE(kth, M_KTRACE);
160	p->p_traceflag &= ~KTRFAC_ACTIVE;
161}
162
163void
164ktrgenio(vp, fd, rw, uio, error)
165	struct vnode *vp;
166	int fd;
167	enum uio_rw rw;
168	struct uio *uio;
169	int error;
170{
171	struct ktr_header *kth;
172	struct ktr_genio ktg;
173	struct proc *p = curproc;	/* XXX */
174
175	if (error)
176		return;
177	p->p_traceflag |= KTRFAC_ACTIVE;
178	kth = ktrgetheader(KTR_GENIO);
179	ktg.ktr_fd = fd;
180	ktg.ktr_rw = rw;
181	kth->ktr_buffer = (caddr_t)&ktg;
182	kth->ktr_len = sizeof(struct ktr_genio);
183	uio->uio_offset = 0;
184	uio->uio_rw = UIO_WRITE;
185
186	ktrwrite(vp, kth, uio);
187	FREE(kth, M_KTRACE);
188	p->p_traceflag &= ~KTRFAC_ACTIVE;
189}
190
191void
192ktrpsig(vp, sig, action, mask, code)
193	struct vnode *vp;
194	int sig;
195	sig_t action;
196	sigset_t *mask;
197	int code;
198{
199	struct ktr_header *kth;
200	struct ktr_psig	kp;
201	struct proc *p = curproc;	/* XXX */
202
203	p->p_traceflag |= KTRFAC_ACTIVE;
204	kth = ktrgetheader(KTR_PSIG);
205	kp.signo = (char)sig;
206	kp.action = action;
207	kp.mask = *mask;
208	kp.code = code;
209	kth->ktr_buffer = (caddr_t)&kp;
210	kth->ktr_len = sizeof (struct ktr_psig);
211
212	ktrwrite(vp, kth, NULL);
213	FREE(kth, M_KTRACE);
214	p->p_traceflag &= ~KTRFAC_ACTIVE;
215}
216
217void
218ktrcsw(vp, out, user)
219	struct vnode *vp;
220	int out, user;
221{
222	struct ktr_header *kth;
223	struct	ktr_csw kc;
224	struct proc *p = curproc;	/* XXX */
225
226	p->p_traceflag |= KTRFAC_ACTIVE;
227	kth = ktrgetheader(KTR_CSW);
228	kc.out = out;
229	kc.user = user;
230	kth->ktr_buffer = (caddr_t)&kc;
231	kth->ktr_len = sizeof (struct ktr_csw);
232
233	ktrwrite(vp, kth, NULL);
234	FREE(kth, M_KTRACE);
235	p->p_traceflag &= ~KTRFAC_ACTIVE;
236}
237#endif
238
239/* Interface and common routines */
240
241/*
242 * ktrace system call
243 */
244#ifndef _SYS_SYSPROTO_H_
245struct ktrace_args {
246	char	*fname;
247	int	ops;
248	int	facs;
249	int	pid;
250};
251#endif
252/* ARGSUSED */
253int
254ktrace(td, uap)
255	struct thread *td;
256	register struct ktrace_args *uap;
257{
258#ifdef KTRACE
259	struct proc *curp = td->td_proc;
260	register struct vnode *vp = NULL;
261	register struct proc *p;
262	struct pgrp *pg;
263	int facs = uap->facs & ~KTRFAC_ROOT;
264	int ops = KTROP(uap->ops);
265	int descend = uap->ops & KTRFLAG_DESCEND;
266	int ret = 0;
267	int flags, error = 0;
268	struct nameidata nd;
269
270	curp->p_traceflag |= KTRFAC_ACTIVE;
271	if (ops != KTROP_CLEAR) {
272		/*
273		 * an operation which requires a file argument.
274		 */
275		NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, uap->fname, td);
276		flags = FREAD | FWRITE | O_NOFOLLOW;
277		error = vn_open(&nd, &flags, 0);
278		if (error) {
279			curp->p_traceflag &= ~KTRFAC_ACTIVE;
280			return (error);
281		}
282		NDFREE(&nd, NDF_ONLY_PNBUF);
283		vp = nd.ni_vp;
284		VOP_UNLOCK(vp, 0, td);
285		if (vp->v_type != VREG) {
286			(void) vn_close(vp, FREAD|FWRITE, curp->p_ucred, td);
287			curp->p_traceflag &= ~KTRFAC_ACTIVE;
288			return (EACCES);
289		}
290	}
291	/*
292	 * Clear all uses of the tracefile
293	 */
294	if (ops == KTROP_CLEARFILE) {
295		sx_slock(&allproc_lock);
296		LIST_FOREACH(p, &allproc, p_list) {
297			if (p->p_tracep == vp) {
298				if (ktrcanset(curp, p)) {
299					p->p_tracep = NULL;
300					p->p_traceflag = 0;
301					(void) vn_close(vp, FREAD|FWRITE,
302						p->p_ucred, td);
303				} else
304					error = EPERM;
305			}
306		}
307		sx_sunlock(&allproc_lock);
308		goto done;
309	}
310	/*
311	 * need something to (un)trace (XXX - why is this here?)
312	 */
313	if (!facs) {
314		error = EINVAL;
315		goto done;
316	}
317	/*
318	 * do it
319	 */
320	if (uap->pid < 0) {
321		/*
322		 * by process group
323		 */
324		pg = pgfind(-uap->pid);
325		if (pg == NULL) {
326			error = ESRCH;
327			goto done;
328		}
329		LIST_FOREACH(p, &pg->pg_members, p_pglist)
330			if (descend)
331				ret |= ktrsetchildren(curp, p, ops, facs, vp);
332			else
333				ret |= ktrops(curp, p, ops, facs, vp);
334	} else {
335		/*
336		 * by pid
337		 */
338		p = pfind(uap->pid);
339		if (p == NULL) {
340			error = ESRCH;
341			goto done;
342		}
343		PROC_UNLOCK(p);
344		if (descend)
345			ret |= ktrsetchildren(curp, p, ops, facs, vp);
346		else
347			ret |= ktrops(curp, p, ops, facs, vp);
348	}
349	if (!ret)
350		error = EPERM;
351done:
352	if (vp != NULL)
353		(void) vn_close(vp, FWRITE, curp->p_ucred, td);
354	curp->p_traceflag &= ~KTRFAC_ACTIVE;
355	return (error);
356#else
357	return ENOSYS;
358#endif
359}
360
361/*
362 * utrace system call
363 */
364/* ARGSUSED */
365int
366utrace(td, uap)
367	struct thread *td;
368	register struct utrace_args *uap;
369{
370
371#ifdef KTRACE
372	struct ktr_header *kth;
373	struct proc *p = curproc;	/* XXX */
374	register caddr_t cp;
375
376	if (!KTRPOINT(p, KTR_USER))
377		return (0);
378	if (uap->len > KTR_USER_MAXLEN)
379		return (EINVAL);
380	p->p_traceflag |= KTRFAC_ACTIVE;
381	kth = ktrgetheader(KTR_USER);
382	MALLOC(cp, caddr_t, uap->len, M_KTRACE, M_WAITOK);
383	if (!copyin(uap->addr, cp, uap->len)) {
384		kth->ktr_buffer = cp;
385		kth->ktr_len = uap->len;
386		ktrwrite(p->p_tracep, kth, NULL);
387	}
388	FREE(kth, M_KTRACE);
389	FREE(cp, M_KTRACE);
390	p->p_traceflag &= ~KTRFAC_ACTIVE;
391
392	return (0);
393#else
394	return (ENOSYS);
395#endif
396}
397
398#ifdef KTRACE
399static int
400ktrops(curp, p, ops, facs, vp)
401	struct proc *p, *curp;
402	int ops, facs;
403	struct vnode *vp;
404{
405
406	if (!ktrcanset(curp, p))
407		return (0);
408	if (ops == KTROP_SET) {
409		if (p->p_tracep != vp) {
410			/*
411			 * if trace file already in use, relinquish
412			 */
413			if (p->p_tracep != NULL)
414				vrele(p->p_tracep);
415			VREF(vp);
416			p->p_tracep = vp;
417		}
418		p->p_traceflag |= facs;
419		if (curp->p_ucred->cr_uid == 0)
420			p->p_traceflag |= KTRFAC_ROOT;
421	} else {
422		/* KTROP_CLEAR */
423		if (((p->p_traceflag &= ~facs) & KTRFAC_MASK) == 0) {
424			/* no more tracing */
425			p->p_traceflag = 0;
426			if (p->p_tracep != NULL) {
427				vrele(p->p_tracep);
428				p->p_tracep = NULL;
429			}
430		}
431	}
432
433	return (1);
434}
435
436static int
437ktrsetchildren(curp, top, ops, facs, vp)
438	struct proc *curp, *top;
439	int ops, facs;
440	struct vnode *vp;
441{
442	register struct proc *p;
443	register int ret = 0;
444
445	p = top;
446	sx_slock(&proctree_lock);
447	for (;;) {
448		ret |= ktrops(curp, p, ops, facs, vp);
449		/*
450		 * If this process has children, descend to them next,
451		 * otherwise do any siblings, and if done with this level,
452		 * follow back up the tree (but not past top).
453		 */
454		if (!LIST_EMPTY(&p->p_children))
455			p = LIST_FIRST(&p->p_children);
456		else for (;;) {
457			if (p == top) {
458				sx_sunlock(&proctree_lock);
459				return (ret);
460			}
461			if (LIST_NEXT(p, p_sibling)) {
462				p = LIST_NEXT(p, p_sibling);
463				break;
464			}
465			p = p->p_pptr;
466		}
467	}
468	/*NOTREACHED*/
469}
470
471static void
472ktrwrite(vp, kth, uio)
473	struct vnode *vp;
474	register struct ktr_header *kth;
475	struct uio *uio;
476{
477	struct uio auio;
478	struct iovec aiov[2];
479	struct thread *td = curthread;	/* XXX */
480	struct proc *p = td->td_proc;	/* XXX */
481	struct mount *mp;
482	int error;
483
484	if (vp == NULL)
485		return;
486	auio.uio_iov = &aiov[0];
487	auio.uio_offset = 0;
488	auio.uio_segflg = UIO_SYSSPACE;
489	auio.uio_rw = UIO_WRITE;
490	aiov[0].iov_base = (caddr_t)kth;
491	aiov[0].iov_len = sizeof(struct ktr_header);
492	auio.uio_resid = sizeof(struct ktr_header);
493	auio.uio_iovcnt = 1;
494	auio.uio_td = curthread;
495	if (kth->ktr_len > 0) {
496		auio.uio_iovcnt++;
497		aiov[1].iov_base = kth->ktr_buffer;
498		aiov[1].iov_len = kth->ktr_len;
499		auio.uio_resid += kth->ktr_len;
500		if (uio != NULL)
501			kth->ktr_len += uio->uio_resid;
502	}
503	vn_start_write(vp, &mp, V_WAIT);
504	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
505	(void)VOP_LEASE(vp, td, p->p_ucred, LEASE_WRITE);
506	error = VOP_WRITE(vp, &auio, IO_UNIT | IO_APPEND, p->p_ucred);
507	if (error == 0 && uio != NULL) {
508		(void)VOP_LEASE(vp, td, p->p_ucred, LEASE_WRITE);
509		error = VOP_WRITE(vp, uio, IO_UNIT | IO_APPEND, p->p_ucred);
510	}
511	VOP_UNLOCK(vp, 0, td);
512	vn_finished_write(mp);
513	if (!error)
514		return;
515	/*
516	 * If error encountered, give up tracing on this vnode.
517	 */
518	log(LOG_NOTICE, "ktrace write failed, errno %d, tracing stopped\n",
519	    error);
520	sx_slock(&allproc_lock);
521	LIST_FOREACH(p, &allproc, p_list) {
522		if (p->p_tracep == vp) {
523			p->p_tracep = NULL;
524			p->p_traceflag = 0;
525			vrele(vp);
526		}
527	}
528	sx_sunlock(&allproc_lock);
529}
530
531/*
532 * Return true if caller has permission to set the ktracing state
533 * of target.  Essentially, the target can't possess any
534 * more permissions than the caller.  KTRFAC_ROOT signifies that
535 * root previously set the tracing status on the target process, and
536 * so, only root may further change it.
537 */
538static int
539ktrcanset(callp, targetp)
540	struct proc *callp, *targetp;
541{
542
543	if (targetp->p_traceflag & KTRFAC_ROOT &&
544	    suser_xxx(NULL, callp, PRISON_ROOT))
545		return (0);
546
547	if (p_candebug(callp, targetp) != 0)
548		return (0);
549
550	return (1);
551}
552
553#endif /* KTRACE */
554