xref: /original-bsd/sys/kern/kern_ktrace.c (revision 982436bd)
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.5 (Berkeley) 07/05/89
18  */
19 
20 #ifdef KTRACE
21 
22 #include "param.h"
23 #include "user.h"
24 #include "proc.h"
25 #include "file.h"
26 #include "vnode.h"
27 #include "ktrace.h"
28 #include "malloc.h"
29 
30 #include "syscalls.c"
31 
32 extern int nsysent;
33 extern char *syscallnames[];
34 
35 int ktrace_nocheck = 1;
36 
37 struct ktr_header *
38 ktrgetheader(type)
39 {
40 	register struct ktr_header *kth;
41 
42 	MALLOC(kth, struct ktr_header *, sizeof (struct ktr_header),
43 		M_TEMP, M_WAITOK);
44 	kth->ktr_type = type;
45 	microtime(&kth->ktr_time);
46 	kth->ktr_pid = u.u_procp->p_pid;
47 	bcopy(u.u_comm, kth->ktr_comm, MAXCOMLEN);
48 	return (kth);
49 }
50 
51 ktrsyscall(vp, code, narg)
52 	struct vnode *vp;
53 {
54 	struct	ktr_header *kth = ktrgetheader(KTR_SYSCALL);
55 	struct	ktr_syscall *ktp;
56 	register len = sizeof(struct ktr_syscall) + (narg * sizeof(int));
57 	int 	*argp, i;
58 
59 	if (kth == NULL)
60 		return;
61 	MALLOC(ktp, struct ktr_syscall *, len, M_TEMP, M_WAITOK);
62 	ktp->ktr_code = code;
63 	ktp->ktr_narg = narg;
64 	argp = (int *)((char *)ktp + sizeof(struct ktr_syscall));
65 	for (i = 0; i < narg; i++)
66 		*argp++ = u.u_arg[i];
67 	kth->ktr_buf = (caddr_t)ktp;
68 	kth->ktr_len = len;
69 	ktrwrite(vp, kth);
70 	FREE(ktp, M_TEMP);
71 	FREE(kth, M_TEMP);
72 }
73 
74 ktrsysret(vp, code)
75 	struct vnode *vp;
76 {
77 	struct ktr_header *kth = ktrgetheader(KTR_SYSRET);
78 	struct ktr_sysret *ktp;
79 
80 	if (kth == NULL)
81 		return;
82 	MALLOC(ktp, struct ktr_sysret *, sizeof(struct ktr_sysret),
83 		M_TEMP , M_WAITOK);
84 	ktp->ktr_code = code;
85 	ktp->ktr_eosys = u.u_eosys;
86 	ktp->ktr_error = u.u_error;
87 	ktp->ktr_retval = u.u_r.r_val1;		/* what about val2 ? */
88 
89 	kth->ktr_buf = (caddr_t)ktp;
90 	kth->ktr_len = sizeof(struct ktr_sysret);
91 
92 	ktrwrite(vp, kth);
93 	FREE(ktp, M_TEMP);
94 	FREE(kth, M_TEMP);
95 }
96 
97 ktrnamei(vp, path)
98 	struct vnode *vp;
99 	char *path;
100 {
101 	struct ktr_header *kth = ktrgetheader(KTR_NAMEI);
102 
103 	if (kth == NULL)
104 		return;
105 	kth->ktr_len = strlen(path);
106 	kth->ktr_buf = path;
107 
108 	ktrwrite(vp, kth);
109 	FREE(kth, M_TEMP);
110 }
111 
112 ktrgenio(vp, fd, rw, iov, len)
113 	struct vnode *vp;
114 	enum uio_rw rw;
115 	register struct iovec *iov;
116 {
117 	struct ktr_header *kth = ktrgetheader(KTR_GENIO);
118 	register struct ktr_genio *ktp;
119 	register caddr_t cp;
120 	register int resid = len, cnt;
121 
122 	if (kth == NULL || u.u_error)
123 		return;
124 	MALLOC(ktp, struct ktr_genio *, sizeof(struct ktr_genio) + len,
125 		M_TEMP, M_WAITOK);
126 	ktp->ktr_fd = fd;
127 	ktp->ktr_rw = rw;
128 	cp = (caddr_t)((char *)ktp + sizeof (struct ktr_genio));
129 	while (resid > 0) {
130 		if ((cnt = iov->iov_len) > resid)
131 			cnt = resid;
132 		if (copyin(iov->iov_base, cp, cnt))
133 			goto done;
134 		cp += cnt;
135 		resid -= cnt;
136 		iov++;
137 	}
138 	kth->ktr_buf = (caddr_t)ktp;
139 	kth->ktr_len = sizeof (struct ktr_genio) + len;
140 
141 	ktrwrite(vp, kth);
142 done:
143 	FREE(kth, M_TEMP);
144 	FREE(ktp, M_TEMP);
145 }
146 
147 /*
148  * ktrace system call
149  */
150 ktrace()
151 {
152 	register struct a {
153 		char	*fname;
154 		int	ops;
155 		int	facs;
156 		int	pid;
157 	} *uap = (struct a *)u.u_ap;
158 	register struct vnode *vp = NULL;
159 	register struct nameidata *ndp = &u.u_nd;
160 	register struct proc *p;
161 	struct pgrp *pg;
162 	register int ops = uap->ops&0x3;
163 	register int facs = uap->facs;
164 	register int ret = 0;
165 
166 	/*
167 	 * Until security implications are thought through,
168 	 * limit tracing to root (unless ktrace_nocheck is set).
169 	 */
170 	if (!ktrace_nocheck && (u.u_error = suser(u.u_cred, &u.u_acflag)))
171 		return;
172 	if (ops != KTROP_CLEAR) {
173 		/*
174 		 * an operation which requires a file argument.
175 		 */
176 		ndp->ni_segflg = UIO_USERSPACE;
177 		ndp->ni_dirp = uap->fname;
178 		if (u.u_error = vn_open(ndp, FREAD|FWRITE, 0))
179 			return;
180 		vp = ndp->ni_vp;
181 		if (vp->v_type != VREG) {
182 			u.u_error = EACCES;
183 			vrele(vp);
184 			return;
185 		}
186 	}
187 	/*
188 	 * Clear all uses of the tracefile
189 	 */
190 	if (ops == KTROP_CLEARFILE) {
191 		for (p = allproc; p != NULL; p = p->p_nxt) {
192 			if (p->p_tracep == vp) {
193 				p->p_flag &= ~SKTR;
194 				p->p_tracep = NULL;
195 				p->p_traceflag = 0;
196 				vrele(vp);
197 			}
198 		}
199 		goto done;
200 	}
201 
202 	/*
203 	 * need something to (un)trace
204 	 */
205 	if (!facs) {
206 		u.u_error = EINVAL;
207 		goto done;
208 	}
209 
210 	if (uap->pid < 0) {
211 		pg = pgfind(-uap->pid);
212 		if (pg == NULL) {
213 			u.u_error = ESRCH;
214 			goto done;
215 		}
216 		for (p = pg->pg_mem; p != NULL; p = p->p_pgrpnxt)
217 			if (uap->ops&KTROP_INHERITFLAG)
218 				ret |= ktrsetchildren(p, ops, facs, vp);
219 			else
220 				ret |= ktrops(p, ops, facs, vp);
221 
222 	} else {
223 		p = pfind(uap->pid);
224 		if (p == NULL) {
225 			u.u_error = ESRCH;
226 			goto done;
227 		}
228 		if (uap->ops&KTROP_INHERITFLAG)
229 			ret |= ktrsetchildren(p, ops, facs, vp);
230 		else
231 			ret |= ktrops(p, ops, facs, vp);
232 	}
233 	if (!ret)
234 		u.u_error = EPERM;
235 done:
236 	if (vp != NULL)
237 		vrele(vp);
238 }
239 
240 ktrops(p, ops, facs, vp)
241 	struct proc *p;
242 	struct vnode *vp;
243 {
244 
245 	if (u.u_uid && u.u_uid != p->p_uid)
246 		return 0;
247 	if (ops == KTROP_SET) {
248 		if (p->p_tracep != vp) {
249 			/*
250 			 * if trace file already in use, relinquish
251 			 */
252 			if (p->p_tracep != NULL)
253 				vrele(p->p_tracep);
254 			VREF(vp);
255 			p->p_tracep = vp;
256 		}
257 		p->p_traceflag |= facs;
258 	} else {
259 		/* KTROP_CLEAR */
260 		if ((p->p_traceflag &= ~facs) == 0) {
261 			if (p->p_tracep != NULL) {
262 				vrele(p->p_tracep);
263 				p->p_tracep = NULL;
264 			}
265 			p->p_flag &= ~SKTR;
266 		}
267 	}
268 
269 	return 1;
270 }
271 
272 ktrsetchildren(top, ops, facs, vp)
273 	struct proc *top;
274 	struct vnode *vp;
275 {
276 	register struct proc *p;
277 	register int ndx;
278 	register int ret = 0;
279 
280 	p = top;
281 	for (;;) {
282 		if ((ret |= ktrops(p, ops, facs, vp)) && ops == KTROP_SET)
283 			p->p_flag |= SKTR;
284 		/*
285 		 * If this process has children, descend to them next,
286 		 * otherwise do any siblings, and if done with this level,
287 		 * follow back up the tree (but not past top).
288 		 */
289 		if (p->p_cptr)
290 			p = p->p_cptr;
291 		else if (p == top)
292 			return ret;
293 		else if (p->p_osptr)
294 			p = p->p_osptr;
295 		else for (;;) {
296 			p = p->p_pptr;
297 			if (p == top)
298 				return ret;
299 			if (p->p_osptr) {
300 				p = p->p_osptr;
301 				break;
302 			}
303 		}
304 	}
305 	/*NOTREACHED*/
306 }
307 
308 ktrwrite(vp, kth)
309 	struct vnode *vp;
310 	register struct ktr_header *kth;
311 {
312 	struct uio auio;
313 	struct iovec aiov[2];
314 	int offset, error;
315 
316 	if (vp == NULL)
317 		return;
318 	auio.uio_iov = &aiov[0];
319 	auio.uio_offset = 0;
320 	auio.uio_segflg = UIO_SYSSPACE;
321 	auio.uio_rw = UIO_WRITE;
322 	aiov[0].iov_base = (caddr_t)kth;
323 	aiov[0].iov_len = sizeof(struct ktr_header);
324 	auio.uio_resid = sizeof(struct ktr_header);
325 	auio.uio_iovcnt = 1;
326 	if (kth->ktr_len > 0) {
327 		auio.uio_iovcnt++;
328 		aiov[1].iov_base = kth->ktr_buf;
329 		aiov[1].iov_len = kth->ktr_len;
330 		auio.uio_resid += kth->ktr_len;
331 	}
332 	error = VOP_WRITE(vp, &auio, &offset, IO_UNIT|IO_APPEND, u.u_cred);
333 }
334 #endif
335