xref: /csrg-svn/sys/kern/kern_ktrace.c (revision 68329)
136359Smarc /*
263174Sbostic  * Copyright (c) 1989, 1993
363174Sbostic  *	The Regents of the University of California.  All rights reserved.
436359Smarc  *
544436Sbostic  * %sccs.include.redist.c%
636359Smarc  *
7*68329Scgd  *	@(#)kern_ktrace.c	8.4 (Berkeley) 02/14/95
836359Smarc  */
936359Smarc 
1036359Smarc #ifdef KTRACE
1136359Smarc 
1256517Sbostic #include <sys/param.h>
13*68329Scgd #include <sys/systm.h>
1456517Sbostic #include <sys/proc.h>
1556517Sbostic #include <sys/file.h>
1656517Sbostic #include <sys/namei.h>
1756517Sbostic #include <sys/vnode.h>
1856517Sbostic #include <sys/ktrace.h>
1956517Sbostic #include <sys/malloc.h>
2056517Sbostic #include <sys/syslog.h>
2136359Smarc 
22*68329Scgd #include <sys/mount.h>
23*68329Scgd #include <sys/syscallargs.h>
24*68329Scgd 
2536359Smarc struct ktr_header *
2636359Smarc ktrgetheader(type)
2760514Storek 	int type;
2836359Smarc {
2936359Smarc 	register struct ktr_header *kth;
3048017Smckusick 	struct proc *p = curproc;	/* XXX */
3136359Smarc 
3236359Smarc 	MALLOC(kth, struct ktr_header *, sizeof (struct ktr_header),
3336359Smarc 		M_TEMP, M_WAITOK);
3436359Smarc 	kth->ktr_type = type;
3537593Smarc 	microtime(&kth->ktr_time);
3647548Skarels 	kth->ktr_pid = p->p_pid;
3747548Skarels 	bcopy(p->p_comm, kth->ktr_comm, MAXCOMLEN);
3836359Smarc 	return (kth);
3936359Smarc }
4036359Smarc 
41*68329Scgd void
42*68329Scgd ktrsyscall(vp, code, argsize, args)
4337728Smckusick 	struct vnode *vp;
44*68329Scgd 	int code, argsize;
45*68329Scgd 	register_t args[];
4636359Smarc {
4753012Smarc 	struct	ktr_header *kth;
4836359Smarc 	struct	ktr_syscall *ktp;
49*68329Scgd 	register len = sizeof(struct ktr_syscall) + argsize;
5053012Smarc 	struct proc *p = curproc;	/* XXX */
51*68329Scgd 	register_t *argp;
52*68329Scgd 	int i;
5336359Smarc 
5453012Smarc 	p->p_traceflag |= KTRFAC_ACTIVE;
5553012Smarc 	kth = ktrgetheader(KTR_SYSCALL);
5636359Smarc 	MALLOC(ktp, struct ktr_syscall *, len, M_TEMP, M_WAITOK);
5736359Smarc 	ktp->ktr_code = code;
58*68329Scgd 	ktp->ktr_argsize = argsize;
59*68329Scgd 	argp = (register_t *)((char *)ktp + sizeof(struct ktr_syscall));
60*68329Scgd 	for (i = 0; i < (argsize / sizeof *argp); i++)
6143444Smckusick 		*argp++ = args[i];
6236359Smarc 	kth->ktr_buf = (caddr_t)ktp;
6336359Smarc 	kth->ktr_len = len;
6437728Smckusick 	ktrwrite(vp, kth);
6536359Smarc 	FREE(ktp, M_TEMP);
6636359Smarc 	FREE(kth, M_TEMP);
6753012Smarc 	p->p_traceflag &= ~KTRFAC_ACTIVE;
6836359Smarc }
6936359Smarc 
70*68329Scgd void
7143444Smckusick ktrsysret(vp, code, error, retval)
7237728Smckusick 	struct vnode *vp;
7343444Smckusick 	int code, error, retval;
7436359Smarc {
7553012Smarc 	struct ktr_header *kth;
7640805Smarc 	struct ktr_sysret ktp;
7753012Smarc 	struct proc *p = curproc;	/* XXX */
7836359Smarc 
7953012Smarc 	p->p_traceflag |= KTRFAC_ACTIVE;
8053012Smarc 	kth = ktrgetheader(KTR_SYSRET);
8140805Smarc 	ktp.ktr_code = code;
8243444Smckusick 	ktp.ktr_error = error;
8343444Smckusick 	ktp.ktr_retval = retval;		/* what about val2 ? */
8436359Smarc 
8540805Smarc 	kth->ktr_buf = (caddr_t)&ktp;
8636359Smarc 	kth->ktr_len = sizeof(struct ktr_sysret);
8736359Smarc 
8837728Smckusick 	ktrwrite(vp, kth);
8936359Smarc 	FREE(kth, M_TEMP);
9053012Smarc 	p->p_traceflag &= ~KTRFAC_ACTIVE;
9136359Smarc }
9236359Smarc 
93*68329Scgd void
9437728Smckusick ktrnamei(vp, path)
9537728Smckusick 	struct vnode *vp;
9636359Smarc 	char *path;
9736359Smarc {
9853012Smarc 	struct ktr_header *kth;
9953012Smarc 	struct proc *p = curproc;	/* XXX */
10036359Smarc 
10153012Smarc 	p->p_traceflag |= KTRFAC_ACTIVE;
10253012Smarc 	kth = ktrgetheader(KTR_NAMEI);
10336359Smarc 	kth->ktr_len = strlen(path);
10436359Smarc 	kth->ktr_buf = path;
10536359Smarc 
10637728Smckusick 	ktrwrite(vp, kth);
10736359Smarc 	FREE(kth, M_TEMP);
10853012Smarc 	p->p_traceflag &= ~KTRFAC_ACTIVE;
10936359Smarc }
11036359Smarc 
111*68329Scgd void
11243444Smckusick ktrgenio(vp, fd, rw, iov, len, error)
11337728Smckusick 	struct vnode *vp;
11443444Smckusick 	int fd;
11537593Smarc 	enum uio_rw rw;
11637593Smarc 	register struct iovec *iov;
11760514Storek 	int len, error;
11837593Smarc {
11953012Smarc 	struct ktr_header *kth;
12037593Smarc 	register struct ktr_genio *ktp;
12137593Smarc 	register caddr_t cp;
12237593Smarc 	register int resid = len, cnt;
12353012Smarc 	struct proc *p = curproc;	/* XXX */
12437593Smarc 
12546424Smarc 	if (error)
12637593Smarc 		return;
12753012Smarc 	p->p_traceflag |= KTRFAC_ACTIVE;
12853012Smarc 	kth = ktrgetheader(KTR_GENIO);
12937593Smarc 	MALLOC(ktp, struct ktr_genio *, sizeof(struct ktr_genio) + len,
13037593Smarc 		M_TEMP, M_WAITOK);
13137593Smarc 	ktp->ktr_fd = fd;
13237593Smarc 	ktp->ktr_rw = rw;
13337593Smarc 	cp = (caddr_t)((char *)ktp + sizeof (struct ktr_genio));
13437593Smarc 	while (resid > 0) {
13537593Smarc 		if ((cnt = iov->iov_len) > resid)
13637593Smarc 			cnt = resid;
13741573Smckusick 		if (copyin(iov->iov_base, cp, (unsigned)cnt))
13837593Smarc 			goto done;
13937593Smarc 		cp += cnt;
14037593Smarc 		resid -= cnt;
14137593Smarc 		iov++;
14237593Smarc 	}
14337593Smarc 	kth->ktr_buf = (caddr_t)ktp;
14437593Smarc 	kth->ktr_len = sizeof (struct ktr_genio) + len;
14537593Smarc 
14637728Smckusick 	ktrwrite(vp, kth);
14737593Smarc done:
14837593Smarc 	FREE(kth, M_TEMP);
14937593Smarc 	FREE(ktp, M_TEMP);
15053012Smarc 	p->p_traceflag &= ~KTRFAC_ACTIVE;
15137593Smarc }
15237593Smarc 
153*68329Scgd void
15440805Smarc ktrpsig(vp, sig, action, mask, code)
15560514Storek 	struct vnode *vp;
15660514Storek 	int sig;
15760514Storek 	sig_t action;
15860514Storek 	int mask, code;
15940805Smarc {
16053012Smarc 	struct ktr_header *kth;
16140805Smarc 	struct ktr_psig	kp;
16253012Smarc 	struct proc *p = curproc;	/* XXX */
16340805Smarc 
16453012Smarc 	p->p_traceflag |= KTRFAC_ACTIVE;
16553012Smarc 	kth = ktrgetheader(KTR_PSIG);
16640805Smarc 	kp.signo = (char)sig;
16740805Smarc 	kp.action = action;
16840805Smarc 	kp.mask = mask;
16940805Smarc 	kp.code = code;
17040805Smarc 	kth->ktr_buf = (caddr_t)&kp;
17140805Smarc 	kth->ktr_len = sizeof (struct ktr_psig);
17240805Smarc 
17340805Smarc 	ktrwrite(vp, kth);
17440805Smarc 	FREE(kth, M_TEMP);
17553012Smarc 	p->p_traceflag &= ~KTRFAC_ACTIVE;
17640805Smarc }
17740805Smarc 
178*68329Scgd void
17953012Smarc ktrcsw(vp, out, user)
18060514Storek 	struct vnode *vp;
18160514Storek 	int out, user;
18253012Smarc {
18353012Smarc 	struct ktr_header *kth;
18453012Smarc 	struct	ktr_csw kc;
18553012Smarc 	struct proc *p = curproc;	/* XXX */
18653012Smarc 
18753012Smarc 	p->p_traceflag |= KTRFAC_ACTIVE;
18853012Smarc 	kth = ktrgetheader(KTR_CSW);
18953012Smarc 	kc.out = out;
19053012Smarc 	kc.user = user;
19153012Smarc 	kth->ktr_buf = (caddr_t)&kc;
19253012Smarc 	kth->ktr_len = sizeof (struct ktr_csw);
19353012Smarc 
19453012Smarc 	ktrwrite(vp, kth);
19553012Smarc 	FREE(kth, M_TEMP);
19653012Smarc 	p->p_traceflag &= ~KTRFAC_ACTIVE;
19753012Smarc }
19853012Smarc 
19940805Smarc /* Interface and common routines */
20040805Smarc 
20136359Smarc /*
20236359Smarc  * ktrace system call
20336359Smarc  */
20443444Smckusick /* ARGSUSED */
205*68329Scgd int
20643444Smckusick ktrace(curp, uap, retval)
20743444Smckusick 	struct proc *curp;
208*68329Scgd 	register struct ktrace_args /* {
209*68329Scgd 		syscallarg(char *) fname;
210*68329Scgd 		syscallarg(int) ops;
211*68329Scgd 		syscallarg(int) facs;
212*68329Scgd 		syscallarg(int) pid;
213*68329Scgd 	} */ *uap;
214*68329Scgd 	register_t *retval;
21543444Smckusick {
21637728Smckusick 	register struct vnode *vp = NULL;
21736359Smarc 	register struct proc *p;
21836359Smarc 	struct pgrp *pg;
219*68329Scgd 	int facs = SCARG(uap, facs) & ~KTRFAC_ROOT;
220*68329Scgd 	int ops = KTROP(SCARG(uap, ops));
221*68329Scgd 	int descend = SCARG(uap, ops) & KTRFLAG_DESCEND;
22246424Smarc 	int ret = 0;
22343444Smckusick 	int error = 0;
22447548Skarels 	struct nameidata nd;
22536359Smarc 
22653012Smarc 	curp->p_traceflag |= KTRFAC_ACTIVE;
22736359Smarc 	if (ops != KTROP_CLEAR) {
22836359Smarc 		/*
22936359Smarc 		 * an operation which requires a file argument.
23036359Smarc 		 */
231*68329Scgd 		NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, fname),
232*68329Scgd 		    curp);
23353012Smarc 		if (error = vn_open(&nd, FREAD|FWRITE, 0)) {
23453012Smarc 			curp->p_traceflag &= ~KTRFAC_ACTIVE;
23544404Skarels 			return (error);
23653012Smarc 		}
23747548Skarels 		vp = nd.ni_vp;
23849914Smckusick 		VOP_UNLOCK(vp);
23937728Smckusick 		if (vp->v_type != VREG) {
24050106Smckusick 			(void) vn_close(vp, FREAD|FWRITE, curp->p_ucred, curp);
24153012Smarc 			curp->p_traceflag &= ~KTRFAC_ACTIVE;
24244404Skarels 			return (EACCES);
24336359Smarc 		}
24436359Smarc 	}
24536359Smarc 	/*
24636359Smarc 	 * Clear all uses of the tracefile
24736359Smarc 	 */
24836359Smarc 	if (ops == KTROP_CLEARFILE) {
24967732Smckusick 		for (p = allproc.lh_first; p != 0; p = p->p_list.le_next) {
25037728Smckusick 			if (p->p_tracep == vp) {
25146424Smarc 				if (ktrcanset(curp, p)) {
25246424Smarc 					p->p_tracep = NULL;
25346424Smarc 					p->p_traceflag = 0;
25450106Smckusick 					(void) vn_close(vp, FREAD|FWRITE,
25550106Smckusick 						p->p_ucred, p);
25646424Smarc 				} else
25746424Smarc 					error = EPERM;
25836359Smarc 			}
25936359Smarc 		}
26036359Smarc 		goto done;
26136359Smarc 	}
26236359Smarc 	/*
26346424Smarc 	 * need something to (un)trace (XXX - why is this here?)
26436359Smarc 	 */
26536359Smarc 	if (!facs) {
26643444Smckusick 		error = EINVAL;
26736359Smarc 		goto done;
26836359Smarc 	}
26940805Smarc 	/*
27046424Smarc 	 * do it
27140805Smarc 	 */
272*68329Scgd 	if (SCARG(uap, pid) < 0) {
27346424Smarc 		/*
27446424Smarc 		 * by process group
27546424Smarc 		 */
276*68329Scgd 		pg = pgfind(-SCARG(uap, pid));
27736359Smarc 		if (pg == NULL) {
27843444Smckusick 			error = ESRCH;
27936359Smarc 			goto done;
28036359Smarc 		}
28167732Smckusick 		for (p = pg->pg_members.lh_first; p != 0; p = p->p_pglist.le_next)
28246424Smarc 			if (descend)
28346424Smarc 				ret |= ktrsetchildren(curp, p, ops, facs, vp);
28436359Smarc 			else
28546424Smarc 				ret |= ktrops(curp, p, ops, facs, vp);
28636359Smarc 
28736359Smarc 	} else {
28846424Smarc 		/*
28946424Smarc 		 * by pid
29046424Smarc 		 */
291*68329Scgd 		p = pfind(SCARG(uap, pid));
29236359Smarc 		if (p == NULL) {
29343444Smckusick 			error = ESRCH;
29436359Smarc 			goto done;
29536359Smarc 		}
29646424Smarc 		if (descend)
29746424Smarc 			ret |= ktrsetchildren(curp, p, ops, facs, vp);
29836359Smarc 		else
29946424Smarc 			ret |= ktrops(curp, p, ops, facs, vp);
30036359Smarc 	}
30137593Smarc 	if (!ret)
30243444Smckusick 		error = EPERM;
30336359Smarc done:
30437728Smckusick 	if (vp != NULL)
30550106Smckusick 		(void) vn_close(vp, FWRITE, curp->p_ucred, curp);
30653012Smarc 	curp->p_traceflag &= ~KTRFAC_ACTIVE;
30744404Skarels 	return (error);
30836359Smarc }
30936359Smarc 
31060514Storek int
31146424Smarc ktrops(curp, p, ops, facs, vp)
31260514Storek 	struct proc *p, *curp;
31360514Storek 	int ops, facs;
31437728Smckusick 	struct vnode *vp;
31536359Smarc {
31637593Smarc 
31746424Smarc 	if (!ktrcanset(curp, p))
31844404Skarels 		return (0);
31936359Smarc 	if (ops == KTROP_SET) {
32040805Smarc 		if (p->p_tracep != vp) {
32136359Smarc 			/*
32236359Smarc 			 * if trace file already in use, relinquish
32336359Smarc 			 */
32436359Smarc 			if (p->p_tracep != NULL)
32537728Smckusick 				vrele(p->p_tracep);
32638423Smarc 			VREF(vp);
32737728Smckusick 			p->p_tracep = vp;
32836359Smarc 		}
32936359Smarc 		p->p_traceflag |= facs;
33047548Skarels 		if (curp->p_ucred->cr_uid == 0)
33146424Smarc 			p->p_traceflag |= KTRFAC_ROOT;
33236359Smarc 	} else {
33336359Smarc 		/* KTROP_CLEAR */
33446424Smarc 		if (((p->p_traceflag &= ~facs) & KTRFAC_MASK) == 0) {
33540805Smarc 			/* no more tracing */
33640805Smarc 			p->p_traceflag = 0;
33736359Smarc 			if (p->p_tracep != NULL) {
33837728Smckusick 				vrele(p->p_tracep);
33936359Smarc 				p->p_tracep = NULL;
34036359Smarc 			}
34136359Smarc 		}
34236359Smarc 	}
34337593Smarc 
34446424Smarc 	return (1);
34536359Smarc }
34637593Smarc 
34746424Smarc ktrsetchildren(curp, top, ops, facs, vp)
34846424Smarc 	struct proc *curp, *top;
34960514Storek 	int ops, facs;
35037728Smckusick 	struct vnode *vp;
35136359Smarc {
35236359Smarc 	register struct proc *p;
35337593Smarc 	register int ret = 0;
35436359Smarc 
35536359Smarc 	p = top;
35636359Smarc 	for (;;) {
35746424Smarc 		ret |= ktrops(curp, p, ops, facs, vp);
35836359Smarc 		/*
35936359Smarc 		 * If this process has children, descend to them next,
36036359Smarc 		 * otherwise do any siblings, and if done with this level,
36136359Smarc 		 * follow back up the tree (but not past top).
36236359Smarc 		 */
36367732Smckusick 		if (p->p_children.lh_first)
36467732Smckusick 			p = p->p_children.lh_first;
36536359Smarc 		else for (;;) {
36636359Smarc 			if (p == top)
36746424Smarc 				return (ret);
36867732Smckusick 			if (p->p_sibling.le_next) {
36967732Smckusick 				p = p->p_sibling.le_next;
37036359Smarc 				break;
37136359Smarc 			}
37267732Smckusick 			p = p->p_pptr;
37336359Smarc 		}
37436359Smarc 	}
37537593Smarc 	/*NOTREACHED*/
37636359Smarc }
37736359Smarc 
37837728Smckusick ktrwrite(vp, kth)
37937728Smckusick 	struct vnode *vp;
38037728Smckusick 	register struct ktr_header *kth;
38136359Smarc {
38237728Smckusick 	struct uio auio;
38337728Smckusick 	struct iovec aiov[2];
38448017Smckusick 	register struct proc *p = curproc;	/* XXX */
38539581Smckusick 	int error;
38637728Smckusick 
38737728Smckusick 	if (vp == NULL)
38837593Smarc 		return;
38937728Smckusick 	auio.uio_iov = &aiov[0];
39037728Smckusick 	auio.uio_offset = 0;
39137728Smckusick 	auio.uio_segflg = UIO_SYSSPACE;
39237728Smckusick 	auio.uio_rw = UIO_WRITE;
39337728Smckusick 	aiov[0].iov_base = (caddr_t)kth;
39437728Smckusick 	aiov[0].iov_len = sizeof(struct ktr_header);
39537728Smckusick 	auio.uio_resid = sizeof(struct ktr_header);
39637728Smckusick 	auio.uio_iovcnt = 1;
39748017Smckusick 	auio.uio_procp = (struct proc *)0;
39836359Smarc 	if (kth->ktr_len > 0) {
39937728Smckusick 		auio.uio_iovcnt++;
40037728Smckusick 		aiov[1].iov_base = kth->ktr_buf;
40137728Smckusick 		aiov[1].iov_len = kth->ktr_len;
40237728Smckusick 		auio.uio_resid += kth->ktr_len;
40336359Smarc 	}
40439581Smckusick 	VOP_LOCK(vp);
40548017Smckusick 	error = VOP_WRITE(vp, &auio, IO_UNIT|IO_APPEND, p->p_ucred);
40639581Smckusick 	VOP_UNLOCK(vp);
40741573Smckusick 	if (!error)
40841573Smckusick 		return;
40941573Smckusick 	/*
41041573Smckusick 	 * If error encountered, give up tracing on this vnode.
41141573Smckusick 	 */
41247548Skarels 	log(LOG_NOTICE, "ktrace write failed, errno %d, tracing stopped\n",
41347548Skarels 	    error);
41467732Smckusick 	for (p = allproc.lh_first; p != 0; p = p->p_list.le_next) {
41541573Smckusick 		if (p->p_tracep == vp) {
41641573Smckusick 			p->p_tracep = NULL;
41741573Smckusick 			p->p_traceflag = 0;
41841573Smckusick 			vrele(vp);
41941573Smckusick 		}
42041573Smckusick 	}
42136359Smarc }
42246424Smarc 
42346424Smarc /*
42446424Smarc  * Return true if caller has permission to set the ktracing state
42546424Smarc  * of target.  Essentially, the target can't possess any
42646424Smarc  * more permissions than the caller.  KTRFAC_ROOT signifies that
42746424Smarc  * root previously set the tracing status on the target process, and
42846424Smarc  * so, only root may further change it.
42946424Smarc  *
43047548Skarels  * TODO: check groups.  use caller effective gid.
43146424Smarc  */
43247548Skarels ktrcanset(callp, targetp)
43347548Skarels 	struct proc *callp, *targetp;
43446424Smarc {
43547548Skarels 	register struct pcred *caller = callp->p_cred;
43647548Skarels 	register struct pcred *target = targetp->p_cred;
43747548Skarels 
43847548Skarels 	if ((caller->pc_ucred->cr_uid == target->p_ruid &&
43946424Smarc 	     target->p_ruid == target->p_svuid &&
44046424Smarc 	     caller->p_rgid == target->p_rgid &&	/* XXX */
44146424Smarc 	     target->p_rgid == target->p_svgid &&
44247548Skarels 	     (targetp->p_traceflag & KTRFAC_ROOT) == 0) ||
44347548Skarels 	     caller->pc_ucred->cr_uid == 0)
44446424Smarc 		return (1);
44546424Smarc 
44646424Smarc 	return (0);
44746424Smarc }
44846424Smarc 
44936359Smarc #endif
450