xref: /original-bsd/sys/kern/kern_ktrace.c (revision f71c8376)
1 /*
2  * Copyright (c) 1989 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  *
7  *	@(#)kern_ktrace.c	7.10 (Berkeley) 02/15/91
8  */
9 
10 #ifdef KTRACE
11 
12 #include "param.h"
13 #include "user.h"
14 #include "proc.h"
15 #include "file.h"
16 #include "vnode.h"
17 #include "ktrace.h"
18 #include "malloc.h"
19 #include "syslog.h"
20 
21 #include "syscalls.c"
22 
23 extern int nsysent;
24 extern char *syscallnames[];
25 
26 struct ktr_header *
27 ktrgetheader(type)
28 {
29 	register struct ktr_header *kth;
30 
31 	MALLOC(kth, struct ktr_header *, sizeof (struct ktr_header),
32 		M_TEMP, M_WAITOK);
33 	kth->ktr_type = type;
34 	microtime(&kth->ktr_time);
35 	kth->ktr_pid = u.u_procp->p_pid;
36 	bcopy(u.u_procp->p_comm, kth->ktr_comm, MAXCOMLEN);
37 	return (kth);
38 }
39 
40 ktrsyscall(vp, code, narg, args)
41 	struct vnode *vp;
42 	int code, narg, args[];
43 {
44 	struct	ktr_header *kth = ktrgetheader(KTR_SYSCALL);
45 	struct	ktr_syscall *ktp;
46 	register len = sizeof(struct ktr_syscall) + (narg * sizeof(int));
47 	int 	*argp, i;
48 
49 	MALLOC(ktp, struct ktr_syscall *, len, M_TEMP, M_WAITOK);
50 	ktp->ktr_code = code;
51 	ktp->ktr_narg = narg;
52 	argp = (int *)((char *)ktp + sizeof(struct ktr_syscall));
53 	for (i = 0; i < narg; i++)
54 		*argp++ = args[i];
55 	kth->ktr_buf = (caddr_t)ktp;
56 	kth->ktr_len = len;
57 	ktrwrite(vp, kth);
58 	FREE(ktp, M_TEMP);
59 	FREE(kth, M_TEMP);
60 }
61 
62 ktrsysret(vp, code, error, retval)
63 	struct vnode *vp;
64 	int code, error, retval;
65 {
66 	struct ktr_header *kth = ktrgetheader(KTR_SYSRET);
67 	struct ktr_sysret ktp;
68 
69 	ktp.ktr_code = code;
70 	ktp.ktr_error = error;
71 	ktp.ktr_retval = retval;		/* what about val2 ? */
72 
73 	kth->ktr_buf = (caddr_t)&ktp;
74 	kth->ktr_len = sizeof(struct ktr_sysret);
75 
76 	ktrwrite(vp, kth);
77 	FREE(kth, M_TEMP);
78 }
79 
80 ktrnamei(vp, path)
81 	struct vnode *vp;
82 	char *path;
83 {
84 	struct ktr_header *kth = ktrgetheader(KTR_NAMEI);
85 
86 	kth->ktr_len = strlen(path);
87 	kth->ktr_buf = path;
88 
89 	ktrwrite(vp, kth);
90 	FREE(kth, M_TEMP);
91 }
92 
93 ktrgenio(vp, fd, rw, iov, len, error)
94 	struct vnode *vp;
95 	int fd;
96 	enum uio_rw rw;
97 	register struct iovec *iov;
98 {
99 	struct ktr_header *kth = ktrgetheader(KTR_GENIO);
100 	register struct ktr_genio *ktp;
101 	register caddr_t cp;
102 	register int resid = len, cnt;
103 
104 	if (error)
105 		return;
106 	MALLOC(ktp, struct ktr_genio *, sizeof(struct ktr_genio) + len,
107 		M_TEMP, M_WAITOK);
108 	ktp->ktr_fd = fd;
109 	ktp->ktr_rw = rw;
110 	cp = (caddr_t)((char *)ktp + sizeof (struct ktr_genio));
111 	while (resid > 0) {
112 		if ((cnt = iov->iov_len) > resid)
113 			cnt = resid;
114 		if (copyin(iov->iov_base, cp, (unsigned)cnt))
115 			goto done;
116 		cp += cnt;
117 		resid -= cnt;
118 		iov++;
119 	}
120 	kth->ktr_buf = (caddr_t)ktp;
121 	kth->ktr_len = sizeof (struct ktr_genio) + len;
122 
123 	ktrwrite(vp, kth);
124 done:
125 	FREE(kth, M_TEMP);
126 	FREE(ktp, M_TEMP);
127 }
128 
129 ktrpsig(vp, sig, action, mask, code)
130 	struct	vnode *vp;
131 	sig_t	action;
132 {
133 	struct ktr_header *kth = ktrgetheader(KTR_PSIG);
134 	struct ktr_psig	kp;
135 
136 	kp.signo = (char)sig;
137 	kp.action = action;
138 	kp.mask = mask;
139 	kp.code = code;
140 	kth->ktr_buf = (caddr_t)&kp;
141 	kth->ktr_len = sizeof (struct ktr_psig);
142 
143 	ktrwrite(vp, kth);
144 	FREE(kth, M_TEMP);
145 }
146 
147 /* Interface and common routines */
148 
149 /*
150  * ktrace system call
151  */
152 /* ARGSUSED */
153 ktrace(curp, uap, retval)
154 	struct proc *curp;
155 	register struct args {
156 		char	*fname;
157 		int	ops;
158 		int	facs;
159 		int	pid;
160 	} *uap;
161 	int *retval;
162 {
163 	register struct vnode *vp = NULL;
164 	register struct nameidata *ndp = &u.u_nd;
165 	register struct proc *p;
166 	struct pgrp *pg;
167 	int facs = uap->facs & ~KTRFAC_ROOT;
168 	int ops = KTROP(uap->ops);
169 	int descend = uap->ops & KTRFLAG_DESCEND;
170 	int ret = 0;
171 	int error = 0;
172 
173 	if (ops != KTROP_CLEAR) {
174 		/*
175 		 * an operation which requires a file argument.
176 		 */
177 		ndp->ni_segflg = UIO_USERSPACE;
178 		ndp->ni_dirp = uap->fname;
179 		if (error = vn_open(ndp, FREAD|FWRITE, 0))
180 			return (error);
181 		vp = ndp->ni_vp;
182 		if (vp->v_type != VREG) {
183 			vrele(vp);
184 			return (EACCES);
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 				if (ktrcanset(curp, p)) {
194 					p->p_tracep = NULL;
195 					p->p_traceflag = 0;
196 					vrele(vp);
197 				} else
198 					error = EPERM;
199 			}
200 		}
201 		goto done;
202 	}
203 	/*
204 	 * need something to (un)trace (XXX - why is this here?)
205 	 */
206 	if (!facs) {
207 		error = EINVAL;
208 		goto done;
209 	}
210 	/*
211 	 * do it
212 	 */
213 	if (uap->pid < 0) {
214 		/*
215 		 * by process group
216 		 */
217 		pg = pgfind(-uap->pid);
218 		if (pg == NULL) {
219 			error = ESRCH;
220 			goto done;
221 		}
222 		for (p = pg->pg_mem; p != NULL; p = p->p_pgrpnxt)
223 			if (descend)
224 				ret |= ktrsetchildren(curp, p, ops, facs, vp);
225 			else
226 				ret |= ktrops(curp, p, ops, facs, vp);
227 
228 	} else {
229 		/*
230 		 * by pid
231 		 */
232 		p = pfind(uap->pid);
233 		if (p == NULL) {
234 			error = ESRCH;
235 			goto done;
236 		}
237 		if (descend)
238 			ret |= ktrsetchildren(curp, p, ops, facs, vp);
239 		else
240 			ret |= ktrops(curp, p, ops, facs, vp);
241 	}
242 	if (!ret)
243 		error = EPERM;
244 done:
245 	if (vp != NULL)
246 		vrele(vp);
247 	return (error);
248 }
249 
250 ktrops(curp, p, ops, facs, vp)
251 	struct proc *curp, *p;
252 	struct vnode *vp;
253 {
254 
255 	if (!ktrcanset(curp, p))
256 		return (0);
257 	if (ops == KTROP_SET) {
258 		if (p->p_tracep != vp) {
259 			/*
260 			 * if trace file already in use, relinquish
261 			 */
262 			if (p->p_tracep != NULL)
263 				vrele(p->p_tracep);
264 			VREF(vp);
265 			p->p_tracep = vp;
266 		}
267 		p->p_traceflag |= facs;
268 		if (curp->p_uid == 0)
269 			p->p_traceflag |= KTRFAC_ROOT;
270 	} else {
271 		/* KTROP_CLEAR */
272 		if (((p->p_traceflag &= ~facs) & KTRFAC_MASK) == 0) {
273 			/* no more tracing */
274 			p->p_traceflag = 0;
275 			if (p->p_tracep != NULL) {
276 				vrele(p->p_tracep);
277 				p->p_tracep = NULL;
278 			}
279 		}
280 	}
281 
282 	return (1);
283 }
284 
285 ktrsetchildren(curp, top, ops, facs, vp)
286 	struct proc *curp, *top;
287 	struct vnode *vp;
288 {
289 	register struct proc *p;
290 	register int ret = 0;
291 
292 	p = top;
293 	for (;;) {
294 		ret |= ktrops(curp, p, ops, facs, vp);
295 		/*
296 		 * If this process has children, descend to them next,
297 		 * otherwise do any siblings, and if done with this level,
298 		 * follow back up the tree (but not past top).
299 		 */
300 		if (p->p_cptr)
301 			p = p->p_cptr;
302 		else if (p == top)
303 			return (ret);
304 		else if (p->p_osptr)
305 			p = p->p_osptr;
306 		else for (;;) {
307 			p = p->p_pptr;
308 			if (p == top)
309 				return (ret);
310 			if (p->p_osptr) {
311 				p = p->p_osptr;
312 				break;
313 			}
314 		}
315 	}
316 	/*NOTREACHED*/
317 }
318 
319 ktrwrite(vp, kth)
320 	struct vnode *vp;
321 	register struct ktr_header *kth;
322 {
323 	struct uio auio;
324 	struct iovec aiov[2];
325 	struct proc *p;
326 	int error;
327 
328 	if (vp == NULL)
329 		return;
330 	auio.uio_iov = &aiov[0];
331 	auio.uio_offset = 0;
332 	auio.uio_segflg = UIO_SYSSPACE;
333 	auio.uio_rw = UIO_WRITE;
334 	aiov[0].iov_base = (caddr_t)kth;
335 	aiov[0].iov_len = sizeof(struct ktr_header);
336 	auio.uio_resid = sizeof(struct ktr_header);
337 	auio.uio_iovcnt = 1;
338 	if (kth->ktr_len > 0) {
339 		auio.uio_iovcnt++;
340 		aiov[1].iov_base = kth->ktr_buf;
341 		aiov[1].iov_len = kth->ktr_len;
342 		auio.uio_resid += kth->ktr_len;
343 	}
344 	VOP_LOCK(vp);
345 	error = VOP_WRITE(vp, &auio, IO_UNIT|IO_APPEND, u.u_cred);
346 	VOP_UNLOCK(vp);
347 	if (!error)
348 		return;
349 	/*
350 	 * If error encountered, give up tracing on this vnode.
351 	 */
352 	log(LOG_NOTICE, "ktrace write failed, errno %d, tracing stopped\n", error);
353 	for (p = allproc; p != NULL; p = p->p_nxt) {
354 		if (p->p_tracep == vp) {
355 			p->p_tracep = NULL;
356 			p->p_traceflag = 0;
357 			vrele(vp);
358 		}
359 	}
360 }
361 
362 /*
363  * Return true if caller has permission to set the ktracing state
364  * of target.  Essentially, the target can't possess any
365  * more permissions than the caller.  KTRFAC_ROOT signifies that
366  * root previously set the tracing status on the target process, and
367  * so, only root may further change it.
368  *
369  * TODO: check groups  (have to wait till group list is moved
370  *       out of u.  use caller effective gid.
371  */
372 ktrcanset(caller, target)
373 	register struct proc *caller, *target;
374 {
375 	if ((caller->p_uid == target->p_ruid &&
376 	     target->p_ruid == target->p_svuid &&
377 	     caller->p_rgid == target->p_rgid &&	/* XXX */
378 	     target->p_rgid == target->p_svgid &&
379 	     (target->p_traceflag & KTRFAC_ROOT) == 0) ||
380 	     caller->p_uid == 0)
381 		return (1);
382 
383 	return (0);
384 }
385 
386 #endif
387