xref: /csrg-svn/sys/kern/kern_ktrace.c (revision 36359)
1*36359Smarc /*
2*36359Smarc  * Copyright (c) 1989 The Regents of the University of California.
3*36359Smarc  * All rights reserved.
4*36359Smarc  *
5*36359Smarc  * Redistribution and use in source and binary forms are permitted
6*36359Smarc  * provided that the above copyright notice and this paragraph are
7*36359Smarc  * duplicated in all such forms and that any documentation,
8*36359Smarc  * advertising materials, and other materials related to such
9*36359Smarc  * distribution and use acknowledge that the software was developed
10*36359Smarc  * by the University of California, Berkeley.  The name of the
11*36359Smarc  * University may not be used to endorse or promote products derived
12*36359Smarc  * from this software without specific prior written permission.
13*36359Smarc  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14*36359Smarc  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15*36359Smarc  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16*36359Smarc  *
17*36359Smarc  *	@(#)kern_ktrace.c	1.1 (Berkeley) 12/14/88
18*36359Smarc  */
19*36359Smarc 
20*36359Smarc #ifdef KTRACE
21*36359Smarc 
22*36359Smarc #include "param.h"
23*36359Smarc #include "systm.h"
24*36359Smarc #include "dir.h"
25*36359Smarc #include "user.h"
26*36359Smarc #include "assym.s"
27*36359Smarc #include "proc.h"
28*36359Smarc #include "seg.h"
29*36359Smarc #include "acct.h"
30*36359Smarc #include "fs.h"
31*36359Smarc #include "inode.h"
32*36359Smarc #include "syslog.h"
33*36359Smarc #include "kernel.h"
34*36359Smarc #include "ktrace.h"
35*36359Smarc #include "malloc.h"
36*36359Smarc 
37*36359Smarc #include "../sys/syscalls.c"
38*36359Smarc 
39*36359Smarc extern int nsysent;
40*36359Smarc extern char *syscallnames[];
41*36359Smarc 
42*36359Smarc struct ktr_header *
43*36359Smarc ktrgetheader(type)
44*36359Smarc {
45*36359Smarc 	register struct ktr_header *kth;
46*36359Smarc 
47*36359Smarc 	MALLOC(kth, struct ktr_header *, sizeof (struct ktr_header),
48*36359Smarc 		M_TEMP, M_WAITOK);
49*36359Smarc 	if (kth == NULL)
50*36359Smarc 		return (NULL);
51*36359Smarc 	kth->ktr_type = type;
52*36359Smarc 	kth->ktr_time = time;
53*36359Smarc 	kth->ktr_pid = u.u_procp->p_pid;
54*36359Smarc 	bcopy(u.u_comm, kth->ktr_comm, MAXCOMLEN);
55*36359Smarc 
56*36359Smarc 	return (kth);
57*36359Smarc }
58*36359Smarc 
59*36359Smarc ktrsyscall(ip, code, narg)
60*36359Smarc 	struct inode *ip;
61*36359Smarc {
62*36359Smarc 	struct	ktr_header *kth = ktrgetheader(KTR_SYSCALL);
63*36359Smarc 	struct	ktr_syscall *ktp;
64*36359Smarc 	register len = sizeof(struct ktr_syscall) + (narg * sizeof(int));
65*36359Smarc 	int 	*argp, i;
66*36359Smarc 
67*36359Smarc 	if (kth == NULL) {
68*36359Smarc 		printf("lost syscall trace - no header\n");	/* DEBUG */
69*36359Smarc 		return;
70*36359Smarc 	}
71*36359Smarc 	MALLOC(ktp, struct ktr_syscall *, len, M_TEMP, M_WAITOK);
72*36359Smarc 	if (ktp == NULL) {
73*36359Smarc 		printf("lost syscall trace - no buffer\n");	/* DEBUG */
74*36359Smarc 		FREE(kth, M_TEMP);
75*36359Smarc 		return;
76*36359Smarc 	}
77*36359Smarc 	ktp->ktr_code = code;
78*36359Smarc 	ktp->ktr_narg = narg;
79*36359Smarc 	argp = (int *)((char *)ktp + sizeof(struct ktr_syscall));
80*36359Smarc 	for (i = 0; i < narg; i++)
81*36359Smarc 		*argp++ = u.u_arg[i];
82*36359Smarc 	kth->ktr_buf = (caddr_t)ktp;
83*36359Smarc 	kth->ktr_len = len;
84*36359Smarc 	ktrwrite(ip, kth);
85*36359Smarc 	FREE(ktp, M_TEMP);
86*36359Smarc 	FREE(kth, M_TEMP);
87*36359Smarc }
88*36359Smarc 
89*36359Smarc ktrsysret(ip, code)
90*36359Smarc 	struct inode *ip;
91*36359Smarc {
92*36359Smarc 	struct ktr_header *kth = ktrgetheader(KTR_SYSRET);
93*36359Smarc 	struct ktr_sysret *ktp;
94*36359Smarc 
95*36359Smarc 	if (kth == NULL) {
96*36359Smarc 		printf("lost syscall ret - no header\n");	/* DEBUG */
97*36359Smarc 		return;
98*36359Smarc 	}
99*36359Smarc 	MALLOC(ktp, struct ktr_sysret *, sizeof(struct ktr_sysret),
100*36359Smarc 		M_TEMP , M_WAITOK);
101*36359Smarc 	if (ktp == NULL) {
102*36359Smarc 		printf("lost syscall ret - no buffer\n");	/* DEBUG */
103*36359Smarc 		FREE(kth, M_TEMP);
104*36359Smarc 		return;
105*36359Smarc 	}
106*36359Smarc 	ktp->ktr_code = code;
107*36359Smarc 	ktp->ktr_eosys = u.u_eosys;
108*36359Smarc 	ktp->ktr_error = u.u_error;
109*36359Smarc 	ktp->ktr_retval = u.u_r.r_val1;		/* what about val2 ? */
110*36359Smarc 
111*36359Smarc 	kth->ktr_buf = (caddr_t)ktp;
112*36359Smarc 	kth->ktr_len = sizeof(struct ktr_sysret);
113*36359Smarc 
114*36359Smarc 	ktrwrite(ip, kth);
115*36359Smarc 	FREE(ktp, M_TEMP);
116*36359Smarc 	FREE(kth, M_TEMP);
117*36359Smarc }
118*36359Smarc 
119*36359Smarc ktrnamei(ip, path)
120*36359Smarc 	struct inode *ip;
121*36359Smarc 	char *path;
122*36359Smarc {
123*36359Smarc 	struct ktr_header *kth = ktrgetheader(KTR_NAMEI);
124*36359Smarc 
125*36359Smarc 	if (kth == NULL) {
126*36359Smarc 		printf("lost namei - no header\n");	/* DEBUG */
127*36359Smarc 		return;
128*36359Smarc 	}
129*36359Smarc 	kth->ktr_len = strlen(path);
130*36359Smarc 	kth->ktr_buf = path;
131*36359Smarc 
132*36359Smarc 	ktrwrite(ip, kth);
133*36359Smarc 	FREE(kth, M_TEMP);
134*36359Smarc }
135*36359Smarc 
136*36359Smarc /*
137*36359Smarc  * ktrace system call
138*36359Smarc  */
139*36359Smarc ktrace()
140*36359Smarc {
141*36359Smarc 	register struct inode *ip = NULL;
142*36359Smarc 	register struct a {
143*36359Smarc 		char	*fname;
144*36359Smarc 		int	ops;
145*36359Smarc 		int	facs;
146*36359Smarc 		pid_t	pid;
147*36359Smarc 	} *uap = (struct a *)u.u_ap;
148*36359Smarc 	register struct nameidata *ndp = &u.u_nd;
149*36359Smarc 	register struct proc *p;
150*36359Smarc 	struct pgrp *pg;
151*36359Smarc 	register int ops = uap->ops&0x3;
152*36359Smarc 	register int facs = uap->facs;
153*36359Smarc 
154*36359Smarc 	/*
155*36359Smarc 	 * Until security implications are thought through,
156*36359Smarc 	 * limit tracing to root.
157*36359Smarc 	 */
158*36359Smarc 	if (!suser()) {
159*36359Smarc 		u.u_error = EACCES;
160*36359Smarc 		return;
161*36359Smarc 	}
162*36359Smarc 	if (ops != KTROP_CLEAR) {
163*36359Smarc 		/*
164*36359Smarc 		 * an operation which requires a file argument.
165*36359Smarc 		 */
166*36359Smarc 		ndp->ni_nameiop = LOOKUP | FOLLOW;
167*36359Smarc 		ndp->ni_segflg = UIO_USERSPACE;
168*36359Smarc 		ndp->ni_dirp = uap->fname;
169*36359Smarc 		ip = namei(ndp);
170*36359Smarc 		if (ip == NULL)
171*36359Smarc 			return;
172*36359Smarc 		if ((ip->i_mode&IFMT) != IFREG) {
173*36359Smarc 			u.u_error = EACCES;
174*36359Smarc 			iput(ip);
175*36359Smarc 			return;
176*36359Smarc 		}
177*36359Smarc 		if (ip->i_fs->fs_ronly) {
178*36359Smarc 			u.u_error = EROFS;
179*36359Smarc 			iput(ip);
180*36359Smarc 			return;
181*36359Smarc 		}
182*36359Smarc 		iunlock(ip);
183*36359Smarc 	}
184*36359Smarc 	/*
185*36359Smarc 	 * Clear all uses of the tracefile
186*36359Smarc 	 */
187*36359Smarc 	if (ops == KTROP_CLEARFILE) {
188*36359Smarc 		for (p = allproc; p != NULL; p = p->p_nxt) {
189*36359Smarc 			if (p->p_tracep == ip) {
190*36359Smarc 				p->p_flag &= ~SKTR;
191*36359Smarc 				p->p_tracep = NULL;
192*36359Smarc 				p->p_traceflag = 0;
193*36359Smarc 				irele(ip);
194*36359Smarc 			}
195*36359Smarc 		}
196*36359Smarc 		goto done;
197*36359Smarc 	}
198*36359Smarc 
199*36359Smarc 	/*
200*36359Smarc 	 * need something to (un)trace
201*36359Smarc 	 */
202*36359Smarc 	if (!facs) {
203*36359Smarc 		u.u_error = EINVAL;
204*36359Smarc 		goto done;
205*36359Smarc 	}
206*36359Smarc 
207*36359Smarc 	if (uap->pid < 0) {
208*36359Smarc 		pg = pgfind(-uap->pid);
209*36359Smarc 		if (pg == NULL) {
210*36359Smarc 			u.u_error = ESRCH;
211*36359Smarc 			goto done;
212*36359Smarc 		}
213*36359Smarc 		for (p = pg->pg_mem; p != NULL; p = p->p_pgrpnxt)
214*36359Smarc 			if (uap->ops&KTROP_INHERITFLAG)
215*36359Smarc 				ktrsetchildren(p, ops, facs, ip);
216*36359Smarc 			else
217*36359Smarc 				ktrops(p, ops, facs, ip);
218*36359Smarc 
219*36359Smarc 	} else {
220*36359Smarc 		p = pfind(uap->pid);
221*36359Smarc 		if (p == NULL) {
222*36359Smarc 			u.u_error = ESRCH;
223*36359Smarc 			goto done;
224*36359Smarc 		}
225*36359Smarc 		if (uap->ops&KTROP_INHERITFLAG)
226*36359Smarc 			ktrsetchildren(p, ops, facs, ip);
227*36359Smarc 		else
228*36359Smarc 			ktrops(p, ops, facs, ip);
229*36359Smarc 	}
230*36359Smarc done:
231*36359Smarc 	if (ip != NULL)
232*36359Smarc 		irele(ip);
233*36359Smarc }
234*36359Smarc 
235*36359Smarc ktrops(p, ops, facs, ip)
236*36359Smarc 	struct proc *p;
237*36359Smarc 	struct inode *ip;
238*36359Smarc {
239*36359Smarc 	if (ops == KTROP_SET) {
240*36359Smarc 		if (p->p_tracep != ip) {
241*36359Smarc 			/*
242*36359Smarc 			 * if trace file already in use, relinquish
243*36359Smarc 			 */
244*36359Smarc 			if (p->p_tracep != NULL)
245*36359Smarc 				irele(p->p_tracep);
246*36359Smarc 			igrab(ip);
247*36359Smarc 			p->p_tracep = ip;
248*36359Smarc 			iunlock(ip);
249*36359Smarc 		}
250*36359Smarc 		p->p_traceflag |= facs;
251*36359Smarc 	} else {
252*36359Smarc 		/* KTROP_CLEAR */
253*36359Smarc 		if ((p->p_traceflag &= ~facs) == 0) {
254*36359Smarc 			if (p->p_tracep != NULL) {
255*36359Smarc 				irele(p->p_tracep);
256*36359Smarc 				p->p_tracep = NULL;
257*36359Smarc 			}
258*36359Smarc 			p->p_flag &= SKTR;
259*36359Smarc 		}
260*36359Smarc 	}
261*36359Smarc }
262*36359Smarc 
263*36359Smarc ktrsetchildren(top, ops, facs, ip)
264*36359Smarc 	struct proc *top;
265*36359Smarc 	struct inode *ip;
266*36359Smarc {
267*36359Smarc 	register struct proc *p;
268*36359Smarc 	register int ndx;
269*36359Smarc 
270*36359Smarc 	p = top;
271*36359Smarc 	for (;;) {
272*36359Smarc 		if (ops == KTROP_SET)
273*36359Smarc 			p->p_flag |= SKTR;
274*36359Smarc 		ktrops(p, ops, facs, ip);
275*36359Smarc 		/*
276*36359Smarc 		 * If this process has children, descend to them next,
277*36359Smarc 		 * otherwise do any siblings, and if done with this level,
278*36359Smarc 		 * follow back up the tree (but not past top).
279*36359Smarc 		 */
280*36359Smarc 		if (p->p_cptr)
281*36359Smarc 			p = p->p_cptr;
282*36359Smarc 		else if (p == top)
283*36359Smarc 			return;
284*36359Smarc 		else if (p->p_osptr)
285*36359Smarc 			p = p->p_osptr;
286*36359Smarc 		else for (;;) {
287*36359Smarc 			p = p->p_pptr;
288*36359Smarc 			if (p == top)
289*36359Smarc 				return;
290*36359Smarc 			if (p->p_osptr) {
291*36359Smarc 				p = p->p_osptr;
292*36359Smarc 				break;
293*36359Smarc 			}
294*36359Smarc 		}
295*36359Smarc 	}
296*36359Smarc }
297*36359Smarc 
298*36359Smarc ktrwrite(ip, kth)
299*36359Smarc 	register struct inode *ip;
300*36359Smarc 	struct ktr_header *kth;
301*36359Smarc {
302*36359Smarc 	int save = u.u_error;
303*36359Smarc 	int osize;
304*36359Smarc 
305*36359Smarc 	ilock(ip);
306*36359Smarc 	osize = ip->i_size;
307*36359Smarc 	u.u_error = 0;
308*36359Smarc 	u.u_error = rdwri(UIO_WRITE, ip, (caddr_t)kth,
309*36359Smarc 			sizeof(struct ktr_header), ip->i_size, 1, (int *)0);
310*36359Smarc 	if (u.u_error) {
311*36359Smarc 		itrunc(ip, (u_long)osize);
312*36359Smarc 		goto end;
313*36359Smarc 	}
314*36359Smarc 	if (kth->ktr_len > 0) {
315*36359Smarc 		u.u_error = rdwri(UIO_WRITE, ip, kth->ktr_buf,
316*36359Smarc 			    kth->ktr_len, ip->i_size, 1, (int *)0);
317*36359Smarc 		if (u.u_error)
318*36359Smarc 			itrunc(ip, (u_long)osize);
319*36359Smarc 	}
320*36359Smarc end:
321*36359Smarc 	u.u_error = save;
322*36359Smarc 	iunlock(ip);
323*36359Smarc }
324*36359Smarc 
325*36359Smarc #endif
326