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