kern_ktrace.c revision 1.33.6.2 1 /* $NetBSD: kern_ktrace.c,v 1.33.6.2 2000/04/30 20:13:33 he Exp $ */
2
3 /*
4 * Copyright (c) 1989, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by the University of
18 * California, Berkeley and its contributors.
19 * 4. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 *
35 * @(#)kern_ktrace.c 8.5 (Berkeley) 5/14/95
36 */
37
38 #include "opt_ktrace.h"
39
40 #ifdef KTRACE
41
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/proc.h>
45 #include <sys/file.h>
46 #include <sys/namei.h>
47 #include <sys/vnode.h>
48 #include <sys/ktrace.h>
49 #include <sys/malloc.h>
50 #include <sys/syslog.h>
51 #include <sys/filedesc.h>
52
53 #include <sys/mount.h>
54 #include <sys/syscallargs.h>
55
56 #include <vm/vm.h> /* XXX for uvmexp, needed by PAGE_SIZE */
57 #include <uvm/uvm.h> /* XXX for uvmexp, needed by PAGE_SIZE */
58
59 void ktrinitheader __P((struct ktr_header *, struct proc *, int));
60 int ktrops __P((struct proc *, struct proc *, int, int, void *));
61 int ktrsetchildren __P((struct proc *, struct proc *, int, int, void *));
62 int ktrwrite __P((struct proc *, void *, struct ktr_header *));
63 int ktrcanset __P((struct proc *, struct proc *));
64
65 void
66 ktrderef(p)
67 struct proc *p;
68 {
69 if (p->p_tracep == NULL)
70 return;
71
72 if (p->p_traceflag & KTRFAC_FD) {
73 struct file *fp = p->p_tracep;
74
75 closef(fp, NULL);
76 } else {
77 struct vnode *vp = p->p_tracep;
78
79 vrele(vp);
80 }
81 p->p_tracep = NULL;
82 p->p_traceflag = 0;
83 }
84
85 void
86 ktradref(p)
87 struct proc *p;
88 {
89 if (p->p_traceflag & KTRFAC_FD) {
90 struct file *fp = p->p_tracep;
91
92 fp->f_count++;
93 } else {
94 struct vnode *vp = p->p_tracep;
95
96 VREF(vp);
97 }
98 }
99
100 void
101 ktrinitheader(kth, p, type)
102 struct ktr_header *kth;
103 struct proc *p;
104 int type;
105 {
106
107 memset(kth, 0, sizeof(*kth));
108 kth->ktr_type = type;
109 microtime(&kth->ktr_time);
110 kth->ktr_pid = p->p_pid;
111 memcpy(kth->ktr_comm, p->p_comm, MAXCOMLEN);
112 }
113
114 void
115 ktrsyscall(v, code, argsize, args)
116 void *v;
117 register_t code;
118 size_t argsize;
119 register_t args[];
120 {
121 struct ktr_header kth;
122 struct ktr_syscall *ktp;
123 struct proc *p = curproc; /* XXX */
124 register_t *argp;
125 size_t len = sizeof(struct ktr_syscall) + argsize;
126 int i;
127
128 p->p_traceflag |= KTRFAC_ACTIVE;
129 ktrinitheader(&kth, p, KTR_SYSCALL);
130 ktp = malloc(len, M_TEMP, M_WAITOK);
131 ktp->ktr_code = code;
132 ktp->ktr_argsize = argsize;
133 argp = (register_t *)((char *)ktp + sizeof(struct ktr_syscall));
134 for (i = 0; i < (argsize / sizeof(*argp)); i++)
135 *argp++ = args[i];
136 kth.ktr_buf = (caddr_t)ktp;
137 kth.ktr_len = len;
138 (void) ktrwrite(p, v, &kth);
139 free(ktp, M_TEMP);
140 p->p_traceflag &= ~KTRFAC_ACTIVE;
141 }
142
143 void
144 ktrsysret(v, code, error, retval)
145 void *v;
146 register_t code;
147 int error;
148 register_t retval;
149 {
150 struct ktr_header kth;
151 struct ktr_sysret ktp;
152 struct proc *p = curproc; /* XXX */
153
154 p->p_traceflag |= KTRFAC_ACTIVE;
155 ktrinitheader(&kth, p, KTR_SYSRET);
156 ktp.ktr_code = code;
157 ktp.ktr_error = error;
158 ktp.ktr_retval = retval; /* what about val2 ? */
159
160 kth.ktr_buf = (caddr_t)&ktp;
161 kth.ktr_len = sizeof(struct ktr_sysret);
162
163 (void) ktrwrite(p, v, &kth);
164 p->p_traceflag &= ~KTRFAC_ACTIVE;
165 }
166
167 void
168 ktrnamei(v, path)
169 void *v;
170 char *path;
171 {
172 struct ktr_header kth;
173 struct proc *p = curproc; /* XXX */
174
175 p->p_traceflag |= KTRFAC_ACTIVE;
176 ktrinitheader(&kth, p, KTR_NAMEI);
177 kth.ktr_len = strlen(path);
178 kth.ktr_buf = path;
179
180 (void) ktrwrite(p, v, &kth);
181 p->p_traceflag &= ~KTRFAC_ACTIVE;
182 }
183
184 void
185 ktremul(v, p, emul)
186 void *v;
187 struct proc *p;
188 char *emul;
189 {
190 struct ktr_header kth;
191
192 p->p_traceflag |= KTRFAC_ACTIVE;
193 ktrinitheader(&kth, p, KTR_EMUL);
194 kth.ktr_len = strlen(emul);
195 kth.ktr_buf = emul;
196
197 (void) ktrwrite(p, v, &kth);
198 p->p_traceflag &= ~KTRFAC_ACTIVE;
199 }
200
201 void
202 ktrgenio(v, fd, rw, iov, len, error)
203 void *v;
204 int fd;
205 enum uio_rw rw;
206 struct iovec *iov;
207 int len, error;
208 {
209 struct ktr_header kth;
210 struct ktr_genio *ktp;
211 caddr_t cp;
212 int resid = len, cnt;
213 struct proc *p = curproc; /* XXX */
214 int buflen;
215
216 if (error)
217 return;
218
219 p->p_traceflag |= KTRFAC_ACTIVE;
220
221 buflen = min(PAGE_SIZE, len + sizeof(struct ktr_genio));
222
223 ktrinitheader(&kth, p, KTR_GENIO);
224 ktp = malloc(buflen, M_TEMP, M_WAITOK);
225 ktp->ktr_fd = fd;
226 ktp->ktr_rw = rw;
227
228 kth.ktr_buf = (caddr_t)ktp;
229
230 cp = (caddr_t)((char *)ktp + sizeof(struct ktr_genio));
231 buflen -= sizeof(struct ktr_genio);
232
233 while (resid > 0) {
234 if (schedflags & PSCHED_SHOULDYIELD)
235 preempt(NULL);
236
237 cnt = min(iov->iov_len, buflen);
238 if (cnt > resid)
239 cnt = resid;
240 if (copyin(iov->iov_base, cp, cnt))
241 break;
242
243 kth.ktr_len = cnt + sizeof(struct ktr_genio);
244
245 if (ktrwrite(p, v, &kth) != 0)
246 break;
247
248 iov->iov_base = (caddr_t)iov->iov_base + cnt;
249 iov->iov_len -= cnt;
250
251 if (iov->iov_len == 0)
252 iov++;
253
254 resid -= cnt;
255 }
256
257 free(ktp, M_TEMP);
258 p->p_traceflag &= ~KTRFAC_ACTIVE;
259 }
260
261 void
262 ktrpsig(v, sig, action, mask, code)
263 void *v;
264 int sig;
265 sig_t action;
266 sigset_t *mask;
267 int code;
268 {
269 struct ktr_header kth;
270 struct ktr_psig kp;
271 struct proc *p = curproc; /* XXX */
272
273 p->p_traceflag |= KTRFAC_ACTIVE;
274 ktrinitheader(&kth, p, KTR_PSIG);
275 kp.signo = (char)sig;
276 kp.action = action;
277 kp.mask = *mask;
278 kp.code = code;
279 kth.ktr_buf = (caddr_t)&kp;
280 kth.ktr_len = sizeof(struct ktr_psig);
281
282 (void) ktrwrite(p, v, &kth);
283 p->p_traceflag &= ~KTRFAC_ACTIVE;
284 }
285
286 void
287 ktrcsw(v, out, user)
288 void *v;
289 int out, user;
290 {
291 struct ktr_header kth;
292 struct ktr_csw kc;
293 struct proc *p = curproc; /* XXX */
294
295 p->p_traceflag |= KTRFAC_ACTIVE;
296 ktrinitheader(&kth, p, KTR_CSW);
297 kc.out = out;
298 kc.user = user;
299 kth.ktr_buf = (caddr_t)&kc;
300 kth.ktr_len = sizeof(struct ktr_csw);
301
302 (void) ktrwrite(p, v, &kth);
303 p->p_traceflag &= ~KTRFAC_ACTIVE;
304 }
305
306 /* Interface and common routines */
307
308 /*
309 * ktrace system call
310 */
311 /* ARGSUSED */
312 int
313 sys_fktrace(curp, v, retval)
314 struct proc *curp;
315 void *v;
316 register_t *retval;
317 {
318 struct sys_fktrace_args /* {
319 syscallarg(int) fd;
320 syscallarg(int) ops;
321 syscallarg(int) facs;
322 syscallarg(int) pid;
323 } */ *uap = v;
324 struct file *fp = NULL;
325 struct proc *p;
326 struct filedesc *fdp = curp->p_fd;
327 struct pgrp *pg;
328 int facs;
329 int ops;
330 int descend;
331 int ret = 0;
332 int error = 0;
333
334 if (((u_int)SCARG(uap, fd)) >= fdp->fd_nfiles ||
335 (fp = fdp->fd_ofiles[SCARG(uap, fd)]) == NULL ||
336 (fp->f_flag & FWRITE) == 0)
337 return (EBADF);
338
339 ops = KTROP(SCARG(uap, ops)) | KTRFLAG_FD;
340 descend = SCARG(uap, ops) & KTRFLAG_DESCEND;
341 facs = SCARG(uap, facs) & ~((unsigned) KTRFAC_ROOT);
342 curp->p_traceflag |= KTRFAC_ACTIVE;
343
344 /*
345 * Clear all uses of the tracefile
346 */
347 if (KTROP(ops) == KTROP_CLEARFILE) {
348 for (p = allproc.lh_first; p != 0; p = p->p_list.le_next) {
349 if (p->p_tracep == fp) {
350 if (ktrcanset(curp, p))
351 ktrderef(p);
352 else
353 error = EPERM;
354 }
355 }
356 goto done;
357 }
358 /*
359 * need something to (un)trace (XXX - why is this here?)
360 */
361 if (!facs) {
362 error = EINVAL;
363 goto done;
364 }
365 /*
366 * do it
367 */
368 if (SCARG(uap, pid) < 0) {
369 /*
370 * by process group
371 */
372 pg = pgfind(-SCARG(uap, pid));
373 if (pg == NULL) {
374 error = ESRCH;
375 goto done;
376 }
377 for (p = LIST_FIRST(&pg->pg_members); p != NULL;
378 p = LIST_NEXT(p, p_pglist)) {
379 if (descend)
380 ret |= ktrsetchildren(curp, p, ops, facs, fp);
381 else
382 ret |= ktrops(curp, p, ops, facs, fp);
383 }
384
385 } else {
386 /*
387 * by pid
388 */
389 p = pfind(SCARG(uap, pid));
390 if (p == NULL) {
391 error = ESRCH;
392 goto done;
393 }
394 if (descend)
395 ret |= ktrsetchildren(curp, p, ops, facs, fp);
396 else
397 ret |= ktrops(curp, p, ops, facs, fp);
398 }
399 if (!ret)
400 error = EPERM;
401 done:
402 curp->p_traceflag &= ~KTRFAC_ACTIVE;
403 return (error);
404 }
405
406 /*
407 * ktrace system call
408 */
409 /* ARGSUSED */
410 int
411 sys_ktrace(curp, v, retval)
412 struct proc *curp;
413 void *v;
414 register_t *retval;
415 {
416 struct sys_ktrace_args /* {
417 syscallarg(const char *) fname;
418 syscallarg(int) ops;
419 syscallarg(int) facs;
420 syscallarg(int) pid;
421 } */ *uap = v;
422 struct vnode *vp = NULL;
423 struct proc *p;
424 struct pgrp *pg;
425 int facs = SCARG(uap, facs) & ~((unsigned) KTRFAC_ROOT);
426 int ops = KTROP(SCARG(uap, ops));
427 int descend = SCARG(uap, ops) & KTRFLAG_DESCEND;
428 int ret = 0;
429 int error = 0;
430 struct nameidata nd;
431
432 curp->p_traceflag |= KTRFAC_ACTIVE;
433 if (ops != KTROP_CLEAR) {
434 /*
435 * an operation which requires a file argument.
436 */
437 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, fname),
438 curp);
439 if ((error = vn_open(&nd, FREAD|FWRITE, 0)) != 0) {
440 curp->p_traceflag &= ~KTRFAC_ACTIVE;
441 return (error);
442 }
443 vp = nd.ni_vp;
444 VOP_UNLOCK(vp, 0);
445 if (vp->v_type != VREG) {
446 (void) vn_close(vp, FREAD|FWRITE, curp->p_ucred, curp);
447 curp->p_traceflag &= ~KTRFAC_ACTIVE;
448 return (EACCES);
449 }
450 }
451 /*
452 * Clear all uses of the tracefile
453 */
454 if (KTROP(ops) == KTROP_CLEARFILE) {
455 for (p = allproc.lh_first; p != 0; p = p->p_list.le_next) {
456 if (p->p_tracep == vp &&
457 !ktrops(curp, p, KTROP_CLEAR, ~0, vp))
458 error = EPERM;
459 }
460 goto done;
461 }
462 /*
463 * need something to (un)trace (XXX - why is this here?)
464 */
465 if (!facs) {
466 error = EINVAL;
467 goto done;
468 }
469 /*
470 * do it
471 */
472 if (SCARG(uap, pid) < 0) {
473 /*
474 * by process group
475 */
476 pg = pgfind(-SCARG(uap, pid));
477 if (pg == NULL) {
478 error = ESRCH;
479 goto done;
480 }
481 for (p = LIST_FIRST(&pg->pg_members); p != NULL;
482 p = LIST_NEXT(p, p_pglist)) {
483 if (descend)
484 ret |= ktrsetchildren(curp, p, ops, facs, vp);
485 else
486 ret |= ktrops(curp, p, ops, facs, vp);
487 }
488
489 } else {
490 /*
491 * by pid
492 */
493 p = pfind(SCARG(uap, pid));
494 if (p == NULL) {
495 error = ESRCH;
496 goto done;
497 }
498 if (descend)
499 ret |= ktrsetchildren(curp, p, ops, facs, vp);
500 else
501 ret |= ktrops(curp, p, ops, facs, vp);
502 }
503 if (!ret)
504 error = EPERM;
505 done:
506 if (vp != NULL)
507 (void) vn_close(vp, FWRITE, curp->p_ucred, curp);
508 curp->p_traceflag &= ~KTRFAC_ACTIVE;
509 return (error);
510 }
511
512 int
513 ktrops(curp, p, ops, facs, v)
514 struct proc *p, *curp;
515 int ops, facs;
516 void *v;
517 {
518
519 if (!ktrcanset(curp, p))
520 return (0);
521 if (KTROP(ops) == KTROP_SET) {
522 if (p->p_tracep != v) {
523 /*
524 * if trace file already in use, relinquish
525 */
526 ktrderef(p);
527 if (ops & KTRFLAG_FD)
528 p->p_traceflag = KTRFAC_FD;
529 p->p_tracep = v;
530 ktradref(p);
531 }
532 p->p_traceflag |= facs;
533 if (curp->p_ucred->cr_uid == 0)
534 p->p_traceflag |= KTRFAC_ROOT;
535 } else {
536 /* KTROP_CLEAR */
537 if (((p->p_traceflag &= ~facs) & KTRFAC_MASK) == 0) {
538 /* no more tracing */
539 ktrderef(p);
540 }
541 }
542
543 /*
544 * Emit an emulation record, every time there is a ktrace
545 * change/attach request.
546 */
547 if (KTRPOINT(p, KTR_EMUL))
548 ktremul(p->p_tracep, p, p->p_emul->e_name);
549
550 return (1);
551 }
552
553 int
554 ktrsetchildren(curp, top, ops, facs, v)
555 struct proc *curp, *top;
556 int ops, facs;
557 void *v;
558 {
559 struct proc *p;
560 int ret = 0;
561
562 p = top;
563 for (;;) {
564 ret |= ktrops(curp, p, ops, facs, v);
565 /*
566 * If this process has children, descend to them next,
567 * otherwise do any siblings, and if done with this level,
568 * follow back up the tree (but not past top).
569 */
570 if (LIST_FIRST(&p->p_children) != NULL)
571 p = LIST_FIRST(&p->p_children);
572 else for (;;) {
573 if (p == top)
574 return (ret);
575 if (LIST_NEXT(p, p_sibling) != NULL) {
576 p = LIST_NEXT(p, p_sibling);
577 break;
578 }
579 p = p->p_pptr;
580 }
581 }
582 /*NOTREACHED*/
583 }
584
585 int
586 ktrwrite(p, v, kth)
587 struct proc *p;
588 void *v;
589 struct ktr_header *kth;
590 {
591 struct uio auio;
592 struct iovec aiov[2];
593 int error;
594
595 if (v == NULL)
596 return (0);
597 auio.uio_iov = &aiov[0];
598 auio.uio_offset = 0;
599 auio.uio_segflg = UIO_SYSSPACE;
600 auio.uio_rw = UIO_WRITE;
601 aiov[0].iov_base = (caddr_t)kth;
602 aiov[0].iov_len = sizeof(struct ktr_header);
603 auio.uio_resid = sizeof(struct ktr_header);
604 auio.uio_iovcnt = 1;
605 auio.uio_procp = (struct proc *)0;
606 if (kth->ktr_len > 0) {
607 auio.uio_iovcnt++;
608 aiov[1].iov_base = kth->ktr_buf;
609 aiov[1].iov_len = kth->ktr_len;
610 auio.uio_resid += kth->ktr_len;
611 }
612 if (p->p_traceflag & KTRFAC_FD) {
613 struct file *fp = v;
614
615 error = (*fp->f_ops->fo_write)(fp, &fp->f_offset, &auio,
616 fp->f_cred, FOF_UPDATE_OFFSET);
617 }
618 else {
619 struct vnode *vp = v;
620
621 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
622 error = VOP_WRITE(vp, &auio, IO_UNIT|IO_APPEND, p->p_ucred);
623 VOP_UNLOCK(vp, 0);
624 }
625 if (error == 0)
626 return (0);
627 /*
628 * If error encountered, give up tracing on this vnode. Don't report
629 * EPIPE as this can easily happen with fktrace()/ktruss.
630 */
631 if (error != EPIPE)
632 log(LOG_NOTICE,
633 "ktrace write failed, errno %d, tracing stopped\n",
634 error);
635 for (p = allproc.lh_first; p != 0; p = p->p_list.le_next) {
636 if (p->p_tracep == v)
637 ktrderef(p);
638 }
639
640 return (error);
641 }
642
643 /*
644 * Return true if caller has permission to set the ktracing state
645 * of target. Essentially, the target can't possess any
646 * more permissions than the caller. KTRFAC_ROOT signifies that
647 * root previously set the tracing status on the target process, and
648 * so, only root may further change it.
649 *
650 * TODO: check groups. use caller effective gid.
651 */
652 int
653 ktrcanset(callp, targetp)
654 struct proc *callp, *targetp;
655 {
656 struct pcred *caller = callp->p_cred;
657 struct pcred *target = targetp->p_cred;
658
659 if ((caller->pc_ucred->cr_uid == target->p_ruid &&
660 target->p_ruid == target->p_svuid &&
661 caller->p_rgid == target->p_rgid && /* XXX */
662 target->p_rgid == target->p_svgid &&
663 (targetp->p_traceflag & KTRFAC_ROOT) == 0) ||
664 caller->pc_ucred->cr_uid == 0)
665 return (1);
666
667 return (0);
668 }
669
670 #endif
671