xref: /original-bsd/sys/kern/kern_ktrace.c (revision 2301fdfb)
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.1 (Berkeley) 12/14/88
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 (!suser()) {
159 		u.u_error = EACCES;
160 		return;
161 	}
162 	if (ops != KTROP_CLEAR) {
163 		/*
164 		 * an operation which requires a file argument.
165 		 */
166 		ndp->ni_nameiop = LOOKUP | FOLLOW;
167 		ndp->ni_segflg = UIO_USERSPACE;
168 		ndp->ni_dirp = uap->fname;
169 		ip = namei(ndp);
170 		if (ip == NULL)
171 			return;
172 		if ((ip->i_mode&IFMT) != IFREG) {
173 			u.u_error = EACCES;
174 			iput(ip);
175 			return;
176 		}
177 		if (ip->i_fs->fs_ronly) {
178 			u.u_error = EROFS;
179 			iput(ip);
180 			return;
181 		}
182 		iunlock(ip);
183 	}
184 	/*
185 	 * Clear all uses of the tracefile
186 	 */
187 	if (ops == KTROP_CLEARFILE) {
188 		for (p = allproc; p != NULL; p = p->p_nxt) {
189 			if (p->p_tracep == ip) {
190 				p->p_flag &= ~SKTR;
191 				p->p_tracep = NULL;
192 				p->p_traceflag = 0;
193 				irele(ip);
194 			}
195 		}
196 		goto done;
197 	}
198 
199 	/*
200 	 * need something to (un)trace
201 	 */
202 	if (!facs) {
203 		u.u_error = EINVAL;
204 		goto done;
205 	}
206 
207 	if (uap->pid < 0) {
208 		pg = pgfind(-uap->pid);
209 		if (pg == NULL) {
210 			u.u_error = ESRCH;
211 			goto done;
212 		}
213 		for (p = pg->pg_mem; p != NULL; p = p->p_pgrpnxt)
214 			if (uap->ops&KTROP_INHERITFLAG)
215 				ktrsetchildren(p, ops, facs, ip);
216 			else
217 				ktrops(p, ops, facs, ip);
218 
219 	} else {
220 		p = pfind(uap->pid);
221 		if (p == NULL) {
222 			u.u_error = ESRCH;
223 			goto done;
224 		}
225 		if (uap->ops&KTROP_INHERITFLAG)
226 			ktrsetchildren(p, ops, facs, ip);
227 		else
228 			ktrops(p, ops, facs, ip);
229 	}
230 done:
231 	if (ip != NULL)
232 		irele(ip);
233 }
234 
235 ktrops(p, ops, facs, ip)
236 	struct proc *p;
237 	struct inode *ip;
238 {
239 	if (ops == KTROP_SET) {
240 		if (p->p_tracep != ip) {
241 			/*
242 			 * if trace file already in use, relinquish
243 			 */
244 			if (p->p_tracep != NULL)
245 				irele(p->p_tracep);
246 			igrab(ip);
247 			p->p_tracep = ip;
248 			iunlock(ip);
249 		}
250 		p->p_traceflag |= facs;
251 	} else {
252 		/* KTROP_CLEAR */
253 		if ((p->p_traceflag &= ~facs) == 0) {
254 			if (p->p_tracep != NULL) {
255 				irele(p->p_tracep);
256 				p->p_tracep = NULL;
257 			}
258 			p->p_flag &= SKTR;
259 		}
260 	}
261 }
262 
263 ktrsetchildren(top, ops, facs, ip)
264 	struct proc *top;
265 	struct inode *ip;
266 {
267 	register struct proc *p;
268 	register int ndx;
269 
270 	p = top;
271 	for (;;) {
272 		if (ops == KTROP_SET)
273 			p->p_flag |= SKTR;
274 		ktrops(p, ops, facs, ip);
275 		/*
276 		 * If this process has children, descend to them next,
277 		 * otherwise do any siblings, and if done with this level,
278 		 * follow back up the tree (but not past top).
279 		 */
280 		if (p->p_cptr)
281 			p = p->p_cptr;
282 		else if (p == top)
283 			return;
284 		else if (p->p_osptr)
285 			p = p->p_osptr;
286 		else for (;;) {
287 			p = p->p_pptr;
288 			if (p == top)
289 				return;
290 			if (p->p_osptr) {
291 				p = p->p_osptr;
292 				break;
293 			}
294 		}
295 	}
296 }
297 
298 ktrwrite(ip, kth)
299 	register struct inode *ip;
300 	struct ktr_header *kth;
301 {
302 	int save = u.u_error;
303 	int osize;
304 
305 	ilock(ip);
306 	osize = ip->i_size;
307 	u.u_error = 0;
308 	u.u_error = rdwri(UIO_WRITE, ip, (caddr_t)kth,
309 			sizeof(struct ktr_header), ip->i_size, 1, (int *)0);
310 	if (u.u_error) {
311 		itrunc(ip, (u_long)osize);
312 		goto end;
313 	}
314 	if (kth->ktr_len > 0) {
315 		u.u_error = rdwri(UIO_WRITE, ip, kth->ktr_buf,
316 			    kth->ktr_len, ip->i_size, 1, (int *)0);
317 		if (u.u_error)
318 			itrunc(ip, (u_long)osize);
319 	}
320 end:
321 	u.u_error = save;
322 	iunlock(ip);
323 }
324 
325 #endif
326