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