xref: /dragonfly/sys/kern/kern_ktrace.c (revision 2d8a3be7)
1 /*
2  * Copyright (c) 1989, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *	This product includes software developed by the University of
16  *	California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  *	@(#)kern_ktrace.c	8.2 (Berkeley) 9/23/93
34  * $FreeBSD: src/sys/kern/kern_ktrace.c,v 1.35.2.6 2002/07/05 22:36:38 darrenr Exp $
35  * $DragonFly: src/sys/kern/kern_ktrace.c,v 1.11 2003/09/29 18:52:06 dillon Exp $
36  */
37 
38 #include "opt_ktrace.h"
39 
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/sysproto.h>
43 #include <sys/kernel.h>
44 #include <sys/proc.h>
45 #include <sys/fcntl.h>
46 #include <sys/lock.h>
47 #include <sys/namei.h>
48 #include <sys/vnode.h>
49 #include <sys/ktrace.h>
50 #include <sys/malloc.h>
51 #include <sys/syslog.h>
52 #include <sys/sysent.h>
53 
54 #include <vm/vm_zone.h>
55 static MALLOC_DEFINE(M_KTRACE, "KTRACE", "KTRACE");
56 
57 #ifdef KTRACE
58 static struct ktr_header *ktrgetheader (int type);
59 static void ktrwrite (struct vnode *, struct ktr_header *, struct uio *);
60 static int ktrcanset (struct proc *,struct proc *);
61 static int ktrsetchildren (struct proc *,struct proc *,int,int,struct vnode *);
62 static int ktrops (struct proc *,struct proc *,int,int,struct vnode *);
63 
64 
65 static struct ktr_header *
66 ktrgetheader(type)
67 	int type;
68 {
69 	struct ktr_header *kth;
70 	struct proc *p = curproc;	/* XXX */
71 
72 	MALLOC(kth, struct ktr_header *, sizeof (struct ktr_header),
73 		M_KTRACE, M_WAITOK);
74 	kth->ktr_type = type;
75 	microtime(&kth->ktr_time);
76 	kth->ktr_pid = p->p_pid;
77 	bcopy(p->p_comm, kth->ktr_comm, MAXCOMLEN + 1);
78 	return (kth);
79 }
80 
81 void
82 ktrsyscall(vp, code, narg, args)
83 	struct vnode *vp;
84 	int code, narg;
85 	register_t args[];
86 {
87 	struct	ktr_header *kth;
88 	struct	ktr_syscall *ktp;
89 	int len = offsetof(struct ktr_syscall, ktr_args) +
90 	    (narg * sizeof(register_t));
91 	struct proc *p = curproc;	/* XXX */
92 	register_t *argp;
93 	int i;
94 
95 	p->p_traceflag |= KTRFAC_ACTIVE;
96 	kth = ktrgetheader(KTR_SYSCALL);
97 	MALLOC(ktp, struct ktr_syscall *, len, M_KTRACE, M_WAITOK);
98 	ktp->ktr_code = code;
99 	ktp->ktr_narg = narg;
100 	argp = &ktp->ktr_args[0];
101 	for (i = 0; i < narg; i++)
102 		*argp++ = args[i];
103 	kth->ktr_buf = (caddr_t)ktp;
104 	kth->ktr_len = len;
105 	ktrwrite(vp, kth, NULL);
106 	FREE(ktp, M_KTRACE);
107 	FREE(kth, M_KTRACE);
108 	p->p_traceflag &= ~KTRFAC_ACTIVE;
109 }
110 
111 void
112 ktrsysret(vp, code, error, retval)
113 	struct vnode *vp;
114 	int code, error;
115 	register_t retval;
116 {
117 	struct ktr_header *kth;
118 	struct ktr_sysret ktp;
119 	struct proc *p = curproc;	/* XXX */
120 
121 	p->p_traceflag |= KTRFAC_ACTIVE;
122 	kth = ktrgetheader(KTR_SYSRET);
123 	ktp.ktr_code = code;
124 	ktp.ktr_error = error;
125 	ktp.ktr_retval = retval;		/* what about val2 ? */
126 
127 	kth->ktr_buf = (caddr_t)&ktp;
128 	kth->ktr_len = sizeof(struct ktr_sysret);
129 
130 	ktrwrite(vp, kth, NULL);
131 	FREE(kth, M_KTRACE);
132 	p->p_traceflag &= ~KTRFAC_ACTIVE;
133 }
134 
135 void
136 ktrnamei(vp, path)
137 	struct vnode *vp;
138 	char *path;
139 {
140 	struct ktr_header *kth;
141 	struct proc *p = curproc;	/* XXX */
142 
143 	/*
144 	 * don't let vp get ripped out from under us
145 	 */
146 	if (vp)
147 		VREF(vp);
148 	p->p_traceflag |= KTRFAC_ACTIVE;
149 	kth = ktrgetheader(KTR_NAMEI);
150 	kth->ktr_len = strlen(path);
151 	kth->ktr_buf = path;
152 
153 	ktrwrite(vp, kth, NULL);
154 	if (vp)
155 		vrele(vp);
156 	FREE(kth, M_KTRACE);
157 	p->p_traceflag &= ~KTRFAC_ACTIVE;
158 }
159 
160 void
161 ktrgenio(vp, fd, rw, uio, error)
162 	struct vnode *vp;
163 	int fd;
164 	enum uio_rw rw;
165 	struct uio *uio;
166 	int error;
167 {
168 	struct ktr_header *kth;
169 	struct ktr_genio ktg;
170 	struct proc *p = curproc;	/* XXX */
171 
172 	if (error)
173 		return;
174 	/*
175 	 * don't let p_tracep get ripped out from under us
176 	 */
177 	if (vp)
178 		VREF(vp);
179 	p->p_traceflag |= KTRFAC_ACTIVE;
180 	kth = ktrgetheader(KTR_GENIO);
181 	ktg.ktr_fd = fd;
182 	ktg.ktr_rw = rw;
183 	kth->ktr_buf = (caddr_t)&ktg;
184 	kth->ktr_len = sizeof(struct ktr_genio);
185 	uio->uio_offset = 0;
186 	uio->uio_rw = UIO_WRITE;
187 
188 	ktrwrite(vp, kth, uio);
189 	if (vp)
190 		vrele(vp);
191 	FREE(kth, M_KTRACE);
192 	p->p_traceflag &= ~KTRFAC_ACTIVE;
193 }
194 
195 void
196 ktrpsig(vp, sig, action, mask, code)
197 	struct vnode *vp;
198 	int sig;
199 	sig_t action;
200 	sigset_t *mask;
201 	int code;
202 {
203 	struct ktr_header *kth;
204 	struct ktr_psig	kp;
205 	struct proc *p = curproc;	/* XXX */
206 
207 	/*
208 	 * don't let vp get ripped out from under us
209 	 */
210 	if (vp)
211 		VREF(vp);
212 	p->p_traceflag |= KTRFAC_ACTIVE;
213 	kth = ktrgetheader(KTR_PSIG);
214 	kp.signo = (char)sig;
215 	kp.action = action;
216 	kp.mask = *mask;
217 	kp.code = code;
218 	kth->ktr_buf = (caddr_t)&kp;
219 	kth->ktr_len = sizeof (struct ktr_psig);
220 
221 	ktrwrite(vp, kth, NULL);
222 	if (vp)
223 		vrele(vp);
224 	FREE(kth, M_KTRACE);
225 	p->p_traceflag &= ~KTRFAC_ACTIVE;
226 }
227 
228 void
229 ktrcsw(vp, out, user)
230 	struct vnode *vp;
231 	int out, user;
232 {
233 	struct ktr_header *kth;
234 	struct	ktr_csw kc;
235 	struct proc *p = curproc;	/* XXX */
236 
237 	/*
238 	 * don't let vp get ripped out from under us
239 	 */
240 	if (vp)
241 		VREF(vp);
242 	p->p_traceflag |= KTRFAC_ACTIVE;
243 	kth = ktrgetheader(KTR_CSW);
244 	kc.out = out;
245 	kc.user = user;
246 	kth->ktr_buf = (caddr_t)&kc;
247 	kth->ktr_len = sizeof (struct ktr_csw);
248 
249 	ktrwrite(vp, kth, NULL);
250 	if (vp)
251 		vrele(vp);
252 	FREE(kth, M_KTRACE);
253 	p->p_traceflag &= ~KTRFAC_ACTIVE;
254 }
255 #endif
256 
257 /* Interface and common routines */
258 
259 /*
260  * ktrace system call
261  */
262 /* ARGSUSED */
263 int
264 ktrace(struct ktrace_args *uap)
265 {
266 #ifdef KTRACE
267 	struct thread *td = curthread;
268 	struct proc *curp = td->td_proc;
269 	struct vnode *vp = NULL;
270 	struct proc *p;
271 	struct pgrp *pg;
272 	int facs = uap->facs & ~KTRFAC_ROOT;
273 	int ops = KTROP(uap->ops);
274 	int descend = uap->ops & KTRFLAG_DESCEND;
275 	int ret = 0;
276 	int error = 0;
277 	struct nameidata nd;
278 
279 	curp->p_traceflag |= KTRFAC_ACTIVE;
280 	if (ops != KTROP_CLEAR) {
281 		/*
282 		 * an operation which requires a file argument.
283 		 */
284 		NDINIT(&nd, NAMEI_LOOKUP, 0, UIO_USERSPACE, uap->fname, td);
285 		error = vn_open(&nd, FREAD|FWRITE|O_NOFOLLOW, 0);
286 		if (error) {
287 			curp->p_traceflag &= ~KTRFAC_ACTIVE;
288 			return (error);
289 		}
290 		NDFREE(&nd, NDF_ONLY_PNBUF);
291 		vp = nd.ni_vp;
292 		VOP_UNLOCK(vp, 0, td);
293 		if (vp->v_type != VREG) {
294 			(void) vn_close(vp, FREAD|FWRITE, td);
295 			curp->p_traceflag &= ~KTRFAC_ACTIVE;
296 			return (EACCES);
297 		}
298 	}
299 	/*
300 	 * Clear all uses of the tracefile.  XXX umm, what happens to the
301 	 * loop if vn_close() blocks?
302 	 */
303 	if (ops == KTROP_CLEARFILE) {
304 		FOREACH_PROC_IN_SYSTEM(p) {
305 			if (p->p_tracep == vp) {
306 				if (ktrcanset(curp, p) && p->p_tracep == vp) {
307 					p->p_tracep = NULL;
308 					p->p_traceflag = 0;
309 					(void) vn_close(vp, FREAD|FWRITE, td);
310 				} else {
311 					error = EPERM;
312 				}
313 			}
314 		}
315 		goto done;
316 	}
317 	/*
318 	 * need something to (un)trace (XXX - why is this here?)
319 	 */
320 	if (!facs) {
321 		error = EINVAL;
322 		goto done;
323 	}
324 	/*
325 	 * do it
326 	 */
327 	if (uap->pid < 0) {
328 		/*
329 		 * by process group
330 		 */
331 		pg = pgfind(-uap->pid);
332 		if (pg == NULL) {
333 			error = ESRCH;
334 			goto done;
335 		}
336 		LIST_FOREACH(p, &pg->pg_members, p_pglist)
337 			if (descend)
338 				ret |= ktrsetchildren(curp, p, ops, facs, vp);
339 			else
340 				ret |= ktrops(curp, p, ops, facs, vp);
341 
342 	} else {
343 		/*
344 		 * by pid
345 		 */
346 		p = pfind(uap->pid);
347 		if (p == NULL) {
348 			error = ESRCH;
349 			goto done;
350 		}
351 		if (descend)
352 			ret |= ktrsetchildren(curp, p, ops, facs, vp);
353 		else
354 			ret |= ktrops(curp, p, ops, facs, vp);
355 	}
356 	if (!ret)
357 		error = EPERM;
358 done:
359 	if (vp != NULL)
360 		(void) vn_close(vp, FWRITE, td);
361 	curp->p_traceflag &= ~KTRFAC_ACTIVE;
362 	return (error);
363 #else
364 	return ENOSYS;
365 #endif
366 }
367 
368 /*
369  * utrace system call
370  */
371 /* ARGSUSED */
372 int
373 utrace(struct utrace_args *uap)
374 {
375 #ifdef KTRACE
376 	struct ktr_header *kth;
377 	struct thread *td = curthread;	/* XXX */
378 	struct proc *p = td->td_proc;
379 	struct vnode *vp;
380 	caddr_t cp;
381 
382 	if (!KTRPOINT(td, KTR_USER))
383 		return (0);
384 	if (SCARG(uap, len) > KTR_USER_MAXLEN)
385 		return (EINVAL);
386 	p->p_traceflag |= KTRFAC_ACTIVE;
387 	/*
388 	 * don't let p_tracep get ripped out from under us while we are
389 	 * writing.
390 	 */
391 	if ((vp = p->p_tracep) != NULL)
392 		VREF(vp);
393 	kth = ktrgetheader(KTR_USER);
394 	MALLOC(cp, caddr_t, uap->len, M_KTRACE, M_WAITOK);
395 	if (!copyin(uap->addr, cp, uap->len)) {
396 		kth->ktr_buf = cp;
397 		kth->ktr_len = uap->len;
398 		ktrwrite(vp, kth, NULL);
399 	}
400 	if (vp)
401 		vrele(vp);
402 	FREE(kth, M_KTRACE);
403 	FREE(cp, M_KTRACE);
404 	p->p_traceflag &= ~KTRFAC_ACTIVE;
405 
406 	return (0);
407 #else
408 	return (ENOSYS);
409 #endif
410 }
411 
412 #ifdef KTRACE
413 static int
414 ktrops(curp, p, ops, facs, vp)
415 	struct proc *p, *curp;
416 	int ops, facs;
417 	struct vnode *vp;
418 {
419 
420 	if (!ktrcanset(curp, p))
421 		return (0);
422 	if (ops == KTROP_SET) {
423 		if (p->p_tracep != vp) {
424 			struct vnode *vtmp;
425 
426 			/*
427 			 * if trace file already in use, relinquish
428 			 */
429 			VREF(vp);
430 			while ((vtmp = p->p_tracep) != NULL) {
431 				p->p_tracep = NULL;
432 				vrele(vtmp);
433 			}
434 			p->p_tracep = vp;
435 		}
436 		p->p_traceflag |= facs;
437 		if (curp->p_ucred->cr_uid == 0)
438 			p->p_traceflag |= KTRFAC_ROOT;
439 	} else {
440 		/* KTROP_CLEAR */
441 		if (((p->p_traceflag &= ~facs) & KTRFAC_MASK) == 0) {
442 			struct vnode *vtmp;
443 
444 			/* no more tracing */
445 			p->p_traceflag = 0;
446 			if ((vtmp = p->p_tracep) != NULL) {
447 				p->p_tracep = NULL;
448 				vrele(vtmp);
449 			}
450 		}
451 	}
452 
453 	return (1);
454 }
455 
456 static int
457 ktrsetchildren(curp, top, ops, facs, vp)
458 	struct proc *curp, *top;
459 	int ops, facs;
460 	struct vnode *vp;
461 {
462 	struct proc *p;
463 	int ret = 0;
464 
465 	p = top;
466 	for (;;) {
467 		ret |= ktrops(curp, p, ops, facs, vp);
468 		/*
469 		 * If this process has children, descend to them next,
470 		 * otherwise do any siblings, and if done with this level,
471 		 * follow back up the tree (but not past top).
472 		 */
473 		if (!LIST_EMPTY(&p->p_children))
474 			p = LIST_FIRST(&p->p_children);
475 		else for (;;) {
476 			if (p == top)
477 				return (ret);
478 			if (LIST_NEXT(p, p_sibling)) {
479 				p = LIST_NEXT(p, p_sibling);
480 				break;
481 			}
482 			p = p->p_pptr;
483 		}
484 	}
485 	/*NOTREACHED*/
486 }
487 
488 static void
489 ktrwrite(struct vnode *vp, struct ktr_header *kth, struct uio *uio)
490 {
491 	struct uio auio;
492 	struct iovec aiov[2];
493 	struct thread *td = curthread;
494 	struct proc *p = td->td_proc;	/* XXX */
495 	int error;
496 
497 	if (vp == NULL)
498 		return;
499 	auio.uio_iov = &aiov[0];
500 	auio.uio_offset = 0;
501 	auio.uio_segflg = UIO_SYSSPACE;
502 	auio.uio_rw = UIO_WRITE;
503 	aiov[0].iov_base = (caddr_t)kth;
504 	aiov[0].iov_len = sizeof(struct ktr_header);
505 	auio.uio_resid = sizeof(struct ktr_header);
506 	auio.uio_iovcnt = 1;
507 	auio.uio_td = curthread;
508 	if (kth->ktr_len > 0) {
509 		auio.uio_iovcnt++;
510 		aiov[1].iov_base = kth->ktr_buf;
511 		aiov[1].iov_len = kth->ktr_len;
512 		auio.uio_resid += kth->ktr_len;
513 		if (uio != NULL)
514 			kth->ktr_len += uio->uio_resid;
515 	}
516 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
517 	(void)VOP_LEASE(vp, td, p->p_ucred, LEASE_WRITE);
518 	error = VOP_WRITE(vp, &auio, IO_UNIT | IO_APPEND, p->p_ucred);
519 	if (error == 0 && uio != NULL) {
520 		(void)VOP_LEASE(vp, td, p->p_ucred, LEASE_WRITE);
521 		error = VOP_WRITE(vp, uio, IO_UNIT | IO_APPEND, p->p_ucred);
522 	}
523 	VOP_UNLOCK(vp, 0, td);
524 	if (!error)
525 		return;
526 	/*
527 	 * If error encountered, give up tracing on this vnode.  XXX what
528 	 * happens to the loop if vrele() blocks?
529 	 */
530 	log(LOG_NOTICE, "ktrace write failed, errno %d, tracing stopped\n",
531 	    error);
532 	FOREACH_PROC_IN_SYSTEM(p) {
533 		if (p->p_tracep == vp) {
534 			p->p_tracep = NULL;
535 			p->p_traceflag = 0;
536 			vrele(vp);
537 		}
538 	}
539 }
540 
541 /*
542  * Return true if caller has permission to set the ktracing state
543  * of target.  Essentially, the target can't possess any
544  * more permissions than the caller.  KTRFAC_ROOT signifies that
545  * root previously set the tracing status on the target process, and
546  * so, only root may further change it.
547  *
548  * TODO: check groups.  use caller effective gid.
549  */
550 static int
551 ktrcanset(struct proc *callp, struct proc *targetp)
552 {
553 	struct ucred *caller = callp->p_ucred;
554 	struct ucred *target = targetp->p_ucred;
555 
556 	if (!PRISON_CHECK(caller, target))
557 		return (0);
558 	if ((caller->cr_uid == target->cr_ruid &&
559 	     target->cr_ruid == target->cr_svuid &&
560 	     caller->cr_rgid == target->cr_rgid &&	/* XXX */
561 	     target->cr_rgid == target->cr_svgid &&
562 	     (targetp->p_traceflag & KTRFAC_ROOT) == 0 &&
563 	     (targetp->p_flag & P_SUGID) == 0) ||
564 	     caller->cr_uid == 0)
565 		return (1);
566 
567 	return (0);
568 }
569 
570 #endif /* KTRACE */
571