xref: /csrg-svn/sys/kern/kern_ktrace.c (revision 37593)
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.3 (Berkeley) 05/01/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 "syscalls.c"
38 
39 extern int nsysent;
40 extern char *syscallnames[];
41 
42 int ktrace_nocheck = 1;
43 
44 struct ktr_header *
45 ktrgetheader(type)
46 {
47 	register struct ktr_header *kth;
48 
49 	MALLOC(kth, struct ktr_header *, sizeof (struct ktr_header),
50 		M_TEMP, M_WAITOK);
51 	if (kth == NULL)
52 		return (NULL);
53 	kth->ktr_type = type;
54 	microtime(&kth->ktr_time);
55 	kth->ktr_pid = u.u_procp->p_pid;
56 	bcopy(u.u_comm, kth->ktr_comm, MAXCOMLEN);
57 
58 	if (kth == NULL)
59 		printf("ktrgetheader: can't malloc header for %d\n", type);
60 	return (kth);
61 }
62 
63 ktrsyscall(ip, code, narg)
64 	struct inode *ip;
65 {
66 	struct	ktr_header *kth = ktrgetheader(KTR_SYSCALL);
67 	struct	ktr_syscall *ktp;
68 	register len = sizeof(struct ktr_syscall) + (narg * sizeof(int));
69 	int 	*argp, i;
70 
71 	if (kth == NULL)
72 		return;
73 	MALLOC(ktp, struct ktr_syscall *, len, M_TEMP, M_WAITOK);
74 	if (ktp == NULL) {
75 		printf("lost syscall trace - no buffer\n");	/* DEBUG */
76 		FREE(kth, M_TEMP);
77 		return;
78 	}
79 	ktp->ktr_code = code;
80 	ktp->ktr_narg = narg;
81 	argp = (int *)((char *)ktp + sizeof(struct ktr_syscall));
82 	for (i = 0; i < narg; i++)
83 		*argp++ = u.u_arg[i];
84 	kth->ktr_buf = (caddr_t)ktp;
85 	kth->ktr_len = len;
86 	ktrwrite(ip, kth);
87 	FREE(ktp, M_TEMP);
88 	FREE(kth, M_TEMP);
89 }
90 
91 ktrsysret(ip, code)
92 	struct inode *ip;
93 {
94 	struct ktr_header *kth = ktrgetheader(KTR_SYSRET);
95 	struct ktr_sysret *ktp;
96 
97 	if (kth == NULL)
98 		return;
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 		return;
127 	kth->ktr_len = strlen(path);
128 	kth->ktr_buf = path;
129 
130 	ktrwrite(ip, kth);
131 	FREE(kth, M_TEMP);
132 }
133 
134 ktrgenio(ip, fd, rw, iov, len)
135 	struct inode *ip;
136 	enum uio_rw rw;
137 	register struct iovec *iov;
138 {
139 	struct ktr_header *kth = ktrgetheader(KTR_GENIO);
140 	register struct ktr_genio *ktp;
141 	register caddr_t cp;
142 	register int resid = len, cnt;
143 
144 	if (kth == NULL || u.u_error)
145 		return;
146 	MALLOC(ktp, struct ktr_genio *, sizeof(struct ktr_genio) + len,
147 		M_TEMP, M_WAITOK);
148 	if (ktp == NULL) {
149 		printf("lost ktr_genio data buffer\n");
150 		FREE(kth, M_TEMP);
151 		return;
152 	}
153 	ktp->ktr_fd = fd;
154 	ktp->ktr_rw = rw;
155 	cp = (caddr_t)((char *)ktp + sizeof (struct ktr_genio));
156 	while (resid > 0) {
157 		if ((cnt = iov->iov_len) > resid)
158 			cnt = resid;
159 		if (copyin(iov->iov_base, cp, cnt))
160 			goto done;
161 		cp += cnt;
162 		resid -= cnt;
163 		iov++;
164 	}
165 	kth->ktr_buf = (caddr_t)ktp;
166 	kth->ktr_len = sizeof (struct ktr_genio) + len;
167 
168 	ktrwrite(ip, kth);
169 done:
170 	FREE(kth, M_TEMP);
171 	FREE(ktp, M_TEMP);
172 }
173 
174 /*
175  * ktrace system call
176  */
177 ktrace()
178 {
179 	register struct inode *ip = NULL;
180 	register struct a {
181 		char	*fname;
182 		int	ops;
183 		int	facs;
184 		int	pid;
185 	} *uap = (struct a *)u.u_ap;
186 	register struct nameidata *ndp = &u.u_nd;
187 	register struct proc *p;
188 	struct pgrp *pg;
189 	register int ops = uap->ops&0x3;
190 	register int facs = uap->facs;
191 	register int ret = 0;
192 
193 	/*
194 	 * Until security implications are thought through,
195 	 * limit tracing to root (unless ktrace_nocheck is set).
196 	 */
197 	if (!ktrace_nocheck && (u.u_error = suser(u.u_cred, &u.u_acflag)))
198 		return;
199 	if (ops != KTROP_CLEAR) {
200 		/*
201 		 * an operation which requires a file argument.
202 		 */
203 		ndp->ni_nameiop = LOOKUP | FOLLOW;
204 		ndp->ni_segflg = UIO_USERSPACE;
205 		ndp->ni_dirp = uap->fname;
206 		ip = namei(ndp);
207 		if (ip == NULL)
208 			return;
209 		if (access(ip, IWRITE)) {
210 			iput(ip);
211 			return;
212 		}
213 		if ((ip->i_mode&IFMT) != IFREG) {
214 			u.u_error = EACCES;
215 			iput(ip);
216 			return;
217 		}
218 		if (ip->i_fs->fs_ronly) {
219 			u.u_error = EROFS;
220 			iput(ip);
221 			return;
222 		}
223 		iunlock(ip);
224 	}
225 	/*
226 	 * Clear all uses of the tracefile
227 	 */
228 	if (ops == KTROP_CLEARFILE) {
229 		for (p = allproc; p != NULL; p = p->p_nxt) {
230 			if (p->p_tracep == ip) {
231 				p->p_flag &= ~SKTR;
232 				p->p_tracep = NULL;
233 				p->p_traceflag = 0;
234 				irele(ip);
235 			}
236 		}
237 		goto done;
238 	}
239 
240 	/*
241 	 * need something to (un)trace
242 	 */
243 	if (!facs) {
244 		u.u_error = EINVAL;
245 		goto done;
246 	}
247 
248 	if (uap->pid < 0) {
249 		pg = pgfind(-uap->pid);
250 		if (pg == NULL) {
251 			u.u_error = ESRCH;
252 			goto done;
253 		}
254 		for (p = pg->pg_mem; p != NULL; p = p->p_pgrpnxt)
255 			if (uap->ops&KTROP_INHERITFLAG)
256 				ret |= ktrsetchildren(p, ops, facs, ip);
257 			else
258 				ret |= ktrops(p, ops, facs, ip);
259 
260 	} else {
261 		p = pfind(uap->pid);
262 		if (p == NULL) {
263 			u.u_error = ESRCH;
264 			goto done;
265 		}
266 		if (uap->ops&KTROP_INHERITFLAG)
267 			ret |= ktrsetchildren(p, ops, facs, ip);
268 		else
269 			ret |= ktrops(p, ops, facs, ip);
270 	}
271 	if (!ret)
272 		u.u_error = EPERM;
273 done:
274 	if (ip != NULL)
275 		irele(ip);
276 }
277 
278 ktrops(p, ops, facs, ip)
279 	struct proc *p;
280 	struct inode *ip;
281 {
282 
283 	if (u.u_uid && u.u_uid != p->p_uid)
284 		return 0;
285 	if (ops == KTROP_SET) {
286 		if (p->p_tracep != ip) {
287 			/*
288 			 * if trace file already in use, relinquish
289 			 */
290 			if (p->p_tracep != NULL)
291 				irele(p->p_tracep);
292 			igrab(ip);
293 			p->p_tracep = ip;
294 			iunlock(ip);
295 		}
296 		p->p_traceflag |= facs;
297 	} else {
298 		/* KTROP_CLEAR */
299 		if ((p->p_traceflag &= ~facs) == 0) {
300 			if (p->p_tracep != NULL) {
301 				irele(p->p_tracep);
302 				p->p_tracep = NULL;
303 			}
304 			p->p_flag &= ~SKTR;
305 		}
306 	}
307 
308 	return 1;
309 }
310 
311 ktrsetchildren(top, ops, facs, ip)
312 	struct proc *top;
313 	struct inode *ip;
314 {
315 	register struct proc *p;
316 	register int ndx;
317 	register int ret = 0;
318 
319 	p = top;
320 	for (;;) {
321 		if ((ret |= ktrops(p, ops, facs, ip)) && ops == KTROP_SET)
322 			p->p_flag |= SKTR;
323 		/*
324 		 * If this process has children, descend to them next,
325 		 * otherwise do any siblings, and if done with this level,
326 		 * follow back up the tree (but not past top).
327 		 */
328 		if (p->p_cptr)
329 			p = p->p_cptr;
330 		else if (p == top)
331 			return ret;
332 		else if (p->p_osptr)
333 			p = p->p_osptr;
334 		else for (;;) {
335 			p = p->p_pptr;
336 			if (p == top)
337 				return ret;
338 			if (p->p_osptr) {
339 				p = p->p_osptr;
340 				break;
341 			}
342 		}
343 	}
344 	/*NOTREACHED*/
345 }
346 
347 ktrwrite(ip, kth)
348 	register struct inode *ip;
349 	struct ktr_header *kth;
350 {
351 	int save = u.u_error;
352 	int osize;
353 
354 	if (ip == NULL)
355 		return;
356 	ilock(ip);
357 	osize = ip->i_size;
358 	u.u_error = 0;
359 	u.u_error = rdwri(UIO_WRITE, ip, (caddr_t)kth,
360 			sizeof(struct ktr_header), ip->i_size, 1, (int *)0);
361 	if (u.u_error) {
362 		itrunc(ip, (u_long)osize);
363 		goto end;
364 	}
365 	if (kth->ktr_len > 0) {
366 		u.u_error = rdwri(UIO_WRITE, ip, kth->ktr_buf,
367 			    kth->ktr_len, ip->i_size, 1, (int *)0);
368 		if (u.u_error)
369 			itrunc(ip, (u_long)osize);
370 	}
371 end:
372 	u.u_error = save;
373 	iunlock(ip);
374 }
375 
376 #endif
377