kern_ktrace.c revision 1.42 1 /* $NetBSD: kern_ktrace.c,v 1.42 2000/05/27 00:40:45 sommerfeld 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 #include <sys/ioctl.h>
53
54 #include <sys/mount.h>
55 #include <sys/syscallargs.h>
56
57 int ktrace_common __P((struct proc *, int, int, int, struct file *));
58 void ktrinitheader __P((struct ktr_header *, struct proc *, int));
59 int ktrops __P((struct proc *, struct proc *, int, int, struct file *));
60 int ktrsetchildren __P((struct proc *, struct proc *, int, int,
61 struct file *));
62 int ktrwrite __P((struct proc *, struct ktr_header *));
63 int ktrcanset __P((struct proc *, struct proc *));
64
65 void
66 ktrderef(p)
67 struct proc *p;
68 {
69 struct file *fp = p->p_tracep;
70 p->p_traceflag = 0;
71 if (fp == NULL)
72 return;
73 FILE_USE(fp);
74 closef(fp, NULL);
75
76 p->p_tracep = NULL;
77 }
78
79 void
80 ktradref(p)
81 struct proc *p;
82 {
83 struct file *fp = p->p_tracep;
84
85 fp->f_count++;
86 }
87
88 void
89 ktrinitheader(kth, p, type)
90 struct ktr_header *kth;
91 struct proc *p;
92 int type;
93 {
94
95 memset(kth, 0, sizeof(*kth));
96 kth->ktr_type = type;
97 microtime(&kth->ktr_time);
98 kth->ktr_pid = p->p_pid;
99 memcpy(kth->ktr_comm, p->p_comm, MAXCOMLEN);
100 }
101
102 void
103 ktrsyscall(p, code, argsize, args)
104 struct proc *p;
105 register_t code;
106 size_t argsize;
107 register_t args[];
108 {
109 struct ktr_header kth;
110 struct ktr_syscall *ktp;
111 register_t *argp;
112 size_t len = sizeof(struct ktr_syscall) + argsize;
113 int i;
114
115 p->p_traceflag |= KTRFAC_ACTIVE;
116 ktrinitheader(&kth, p, KTR_SYSCALL);
117 ktp = malloc(len, M_TEMP, M_WAITOK);
118 ktp->ktr_code = code;
119 ktp->ktr_argsize = argsize;
120 argp = (register_t *)((char *)ktp + sizeof(struct ktr_syscall));
121 for (i = 0; i < (argsize / sizeof(*argp)); i++)
122 *argp++ = args[i];
123 kth.ktr_buf = (caddr_t)ktp;
124 kth.ktr_len = len;
125 (void) ktrwrite(p, &kth);
126 free(ktp, M_TEMP);
127 p->p_traceflag &= ~KTRFAC_ACTIVE;
128 }
129
130 void
131 ktrsysret(p, code, error, retval)
132 struct proc *p;
133 register_t code;
134 int error;
135 register_t retval;
136 {
137 struct ktr_header kth;
138 struct ktr_sysret ktp;
139
140 p->p_traceflag |= KTRFAC_ACTIVE;
141 ktrinitheader(&kth, p, KTR_SYSRET);
142 ktp.ktr_code = code;
143 ktp.ktr_eosys = 0; /* XXX unused */
144 ktp.ktr_error = error;
145 ktp.ktr_retval = retval; /* what about val2 ? */
146
147 kth.ktr_buf = (caddr_t)&ktp;
148 kth.ktr_len = sizeof(struct ktr_sysret);
149
150 (void) ktrwrite(p, &kth);
151 p->p_traceflag &= ~KTRFAC_ACTIVE;
152 }
153
154 void
155 ktrnamei(p, path)
156 struct proc *p;
157 char *path;
158 {
159 struct ktr_header kth;
160
161 p->p_traceflag |= KTRFAC_ACTIVE;
162 ktrinitheader(&kth, p, KTR_NAMEI);
163 kth.ktr_len = strlen(path);
164 kth.ktr_buf = path;
165
166 (void) ktrwrite(p, &kth);
167 p->p_traceflag &= ~KTRFAC_ACTIVE;
168 }
169
170 void
171 ktremul(p)
172 struct proc *p;
173 {
174 struct ktr_header kth;
175 char *emul = p->p_emul->e_name;
176
177 p->p_traceflag |= KTRFAC_ACTIVE;
178 ktrinitheader(&kth, p, KTR_EMUL);
179 kth.ktr_len = strlen(emul);
180 kth.ktr_buf = emul;
181
182 (void) ktrwrite(p, &kth);
183 p->p_traceflag &= ~KTRFAC_ACTIVE;
184 }
185
186 void
187 ktrgenio(p, fd, rw, iov, len, error)
188 struct proc *p;
189 int fd;
190 enum uio_rw rw;
191 struct iovec *iov;
192 int len, error;
193 {
194 struct ktr_header kth;
195 struct ktr_genio *ktp;
196 caddr_t cp;
197 int resid = len, cnt;
198 int buflen;
199
200 if (error)
201 return;
202
203 p->p_traceflag |= KTRFAC_ACTIVE;
204
205 buflen = min(PAGE_SIZE, len + sizeof(struct ktr_genio));
206
207 ktrinitheader(&kth, p, KTR_GENIO);
208 ktp = malloc(buflen, M_TEMP, M_WAITOK);
209 ktp->ktr_fd = fd;
210 ktp->ktr_rw = rw;
211
212 kth.ktr_buf = (caddr_t)ktp;
213
214 cp = (caddr_t)((char *)ktp + sizeof(struct ktr_genio));
215 buflen -= sizeof(struct ktr_genio);
216
217 while (resid > 0) {
218 if (curcpu()->ci_schedstate.spc_flags & SPCF_SHOULDYIELD)
219 preempt(NULL);
220
221 cnt = min(iov->iov_len, buflen);
222 if (cnt > resid)
223 cnt = resid;
224 if (copyin(iov->iov_base, cp, cnt))
225 break;
226
227 kth.ktr_len = cnt + sizeof(struct ktr_genio);
228
229 if (__predict_false(ktrwrite(p, &kth) != 0))
230 break;
231
232 iov->iov_base = (caddr_t)iov->iov_base + cnt;
233 iov->iov_len -= cnt;
234
235 if (iov->iov_len == 0)
236 iov++;
237
238 resid -= cnt;
239 }
240
241 free(ktp, M_TEMP);
242 p->p_traceflag &= ~KTRFAC_ACTIVE;
243 }
244
245 void
246 ktrpsig(p, sig, action, mask, code)
247 struct proc *p;
248 int sig;
249 sig_t action;
250 sigset_t *mask;
251 int code;
252 {
253 struct ktr_header kth;
254 struct ktr_psig kp;
255
256 p->p_traceflag |= KTRFAC_ACTIVE;
257 ktrinitheader(&kth, p, KTR_PSIG);
258 kp.signo = (char)sig;
259 kp.action = action;
260 kp.mask = *mask;
261 kp.code = code;
262 kth.ktr_buf = (caddr_t)&kp;
263 kth.ktr_len = sizeof(struct ktr_psig);
264
265 (void) ktrwrite(p, &kth);
266 p->p_traceflag &= ~KTRFAC_ACTIVE;
267 }
268
269 void
270 ktrcsw(p, out, user)
271 struct proc *p;
272 int out, user;
273 {
274 struct ktr_header kth;
275 struct ktr_csw kc;
276
277 p->p_traceflag |= KTRFAC_ACTIVE;
278 ktrinitheader(&kth, p, KTR_CSW);
279 kc.out = out;
280 kc.user = user;
281 kth.ktr_buf = (caddr_t)&kc;
282 kth.ktr_len = sizeof(struct ktr_csw);
283
284 (void) ktrwrite(p, &kth);
285 p->p_traceflag &= ~KTRFAC_ACTIVE;
286 }
287
288 /* Interface and common routines */
289
290 int
291 ktrace_common (curp, ops, facs, pid, fp)
292 struct proc *curp;
293 int ops, facs, pid;
294 struct file *fp;
295 {
296 int ret = 0;
297 int error = 0;
298 int one = 1;
299 int descend;
300 struct proc *p;
301 struct pgrp *pg;
302
303 curp->p_traceflag |= KTRFAC_ACTIVE;
304 descend = ops & KTRFLAG_DESCEND;
305 facs = facs & ~((unsigned) KTRFAC_ROOT);
306
307 /*
308 * Clear all uses of the tracefile
309 */
310 if (KTROP(ops) == KTROP_CLEARFILE) {
311 proclist_lock_read();
312 for (p = LIST_FIRST(&allproc); p != NULL;
313 p = LIST_NEXT(p, p_list)) {
314 if (p->p_tracep == fp) {
315 if (ktrcanset(curp, p))
316 ktrderef(p);
317 else
318 error = EPERM;
319 }
320 }
321 proclist_unlock_read();
322 goto done;
323 }
324
325 /*
326 * Mark fp non-blocking, to avoid problems from possible deadlocks.
327 */
328
329 fp->f_flag |= FNONBLOCK;
330 (*fp->f_ops->fo_ioctl)(fp, FIONBIO, (caddr_t)&one, curp);
331
332
333 /*
334 * need something to (un)trace (XXX - why is this here?)
335 */
336 if (!facs) {
337 error = EINVAL;
338 goto done;
339 }
340 /*
341 * do it
342 */
343 if (pid < 0) {
344 /*
345 * by process group
346 */
347 pg = pgfind(-pid);
348 if (pg == NULL) {
349 error = ESRCH;
350 goto done;
351 }
352 for (p = LIST_FIRST(&pg->pg_members); p != NULL;
353 p = LIST_NEXT(p, p_pglist)) {
354 if (descend)
355 ret |= ktrsetchildren(curp, p, ops, facs, fp);
356 else
357 ret |= ktrops(curp, p, ops, facs, fp);
358 }
359
360 } else {
361 /*
362 * by pid
363 */
364 p = pfind(pid);
365 if (p == NULL) {
366 error = ESRCH;
367 goto done;
368 }
369 if (descend)
370 ret |= ktrsetchildren(curp, p, ops, facs, fp);
371 else
372 ret |= ktrops(curp, p, ops, facs, fp);
373 }
374 if (!ret)
375 error = EPERM;
376 done:
377 curp->p_traceflag &= ~KTRFAC_ACTIVE;
378 return (error);
379 }
380
381 /*
382 * ktrace system call
383 */
384 /* ARGSUSED */
385 int
386 sys_fktrace(curp, v, retval)
387 struct proc *curp;
388 void *v;
389 register_t *retval;
390 {
391 struct sys_fktrace_args /* {
392 syscallarg(int) fd;
393 syscallarg(int) ops;
394 syscallarg(int) facs;
395 syscallarg(int) pid;
396 } */ *uap = v;
397 struct file *fp = NULL;
398 struct filedesc *fdp = curp->p_fd;
399
400 if (((u_int)SCARG(uap, fd)) >= fdp->fd_nfiles ||
401 (fp = fdp->fd_ofiles[SCARG(uap, fd)]) == NULL ||
402 (fp->f_flag & FWRITE) == 0)
403 return (EBADF);
404
405 return ktrace_common(curp, SCARG(uap, ops),
406 SCARG(uap, facs), SCARG(uap, pid), fp);
407 }
408
409 /*
410 * ktrace system call
411 */
412 /* ARGSUSED */
413 int
414 sys_ktrace(curp, v, retval)
415 struct proc *curp;
416 void *v;
417 register_t *retval;
418 {
419 struct sys_ktrace_args /* {
420 syscallarg(const char *) fname;
421 syscallarg(int) ops;
422 syscallarg(int) facs;
423 syscallarg(int) pid;
424 } */ *uap = v;
425 struct vnode *vp = NULL;
426 struct file *fp = NULL;
427 int fd;
428 int ops = SCARG(uap, ops);
429 int error = 0;
430 struct nameidata nd;
431
432 ops = KTROP(ops) | (ops & KTRFLAG_DESCEND);
433
434 curp->p_traceflag |= KTRFAC_ACTIVE;
435 if (ops != KTROP_CLEAR) {
436 /*
437 * an operation which requires a file argument.
438 */
439 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, fname),
440 curp);
441 if ((error = vn_open(&nd, FREAD|FWRITE, 0)) != 0) {
442 curp->p_traceflag &= ~KTRFAC_ACTIVE;
443 return (error);
444 }
445 vp = nd.ni_vp;
446 VOP_UNLOCK(vp, 0);
447 if (vp->v_type != VREG) {
448 (void) vn_close(vp, FREAD|FWRITE, curp->p_ucred, curp);
449 curp->p_traceflag &= ~KTRFAC_ACTIVE;
450 return (EACCES);
451 }
452 /*
453 * XXX This uses up a file descriptor slot in the
454 * tracing process for the duration of this syscall.
455 * This is not expected to be a problem. If
456 * falloc(NULL, ...) DTRT we could skip that part, but
457 * that would require changing its interface to allow
458 * the caller to pass in a ucred..
459 *
460 * This will FILE_USE the fp it returns, if any.
461 * Keep it in use until we return.
462 */
463 if ((error = falloc(curp, &fp, &fd)) != 0)
464 goto done;
465
466 fp->f_flag = FWRITE|FAPPEND;
467 fp->f_type = DTYPE_VNODE;
468 fp->f_ops = &vnops;
469 fp->f_data = (caddr_t)vp;
470 vp = NULL;
471 }
472 error = ktrace_common(curp, SCARG(uap, ops), SCARG(uap, facs),
473 SCARG(uap, pid), fp);
474 done:
475 if (vp != NULL)
476 (void) vn_close(vp, FWRITE, curp->p_ucred, curp);
477 if (fp != NULL) {
478 fdrelease(curp, fd); /* release fd table slot */
479 FILE_UNUSE(fp, curp); /* release file */
480 }
481 return (error);
482 }
483
484 int
485 ktrops(curp, p, ops, facs, fp)
486 struct proc *p, *curp;
487 int ops, facs;
488 struct file *fp;
489 {
490
491 if (!ktrcanset(curp, p))
492 return (0);
493 if (KTROP(ops) == KTROP_SET) {
494 if (p->p_tracep != fp) {
495 /*
496 * if trace file already in use, relinquish
497 */
498 ktrderef(p);
499 p->p_tracep = fp;
500 ktradref(p);
501 }
502 p->p_traceflag |= facs;
503 if (curp->p_ucred->cr_uid == 0)
504 p->p_traceflag |= KTRFAC_ROOT;
505 } else {
506 /* KTROP_CLEAR */
507 if (((p->p_traceflag &= ~facs) & KTRFAC_MASK) == 0) {
508 /* no more tracing */
509 ktrderef(p);
510 }
511 }
512
513 /*
514 * Emit an emulation record, every time there is a ktrace
515 * change/attach request.
516 */
517 if (KTRPOINT(p, KTR_EMUL))
518 ktremul(p);
519
520 return (1);
521 }
522
523 int
524 ktrsetchildren(curp, top, ops, facs, fp)
525 struct proc *curp, *top;
526 int ops, facs;
527 struct file *fp;
528 {
529 struct proc *p;
530 int ret = 0;
531
532 p = top;
533 for (;;) {
534 ret |= ktrops(curp, p, ops, facs, fp);
535 /*
536 * If this process has children, descend to them next,
537 * otherwise do any siblings, and if done with this level,
538 * follow back up the tree (but not past top).
539 */
540 if (LIST_FIRST(&p->p_children) != NULL)
541 p = LIST_FIRST(&p->p_children);
542 else for (;;) {
543 if (p == top)
544 return (ret);
545 if (LIST_NEXT(p, p_sibling) != NULL) {
546 p = LIST_NEXT(p, p_sibling);
547 break;
548 }
549 p = p->p_pptr;
550 }
551 }
552 /*NOTREACHED*/
553 }
554
555 int
556 ktrwrite(p, kth)
557 struct proc *p;
558 struct ktr_header *kth;
559 {
560 struct uio auio;
561 struct iovec aiov[2];
562 int error, tries;
563 struct file *fp = p->p_tracep;
564
565 if (fp == NULL)
566 return 0;
567
568 auio.uio_iov = &aiov[0];
569 auio.uio_offset = 0;
570 auio.uio_segflg = UIO_SYSSPACE;
571 auio.uio_rw = UIO_WRITE;
572 aiov[0].iov_base = (caddr_t)kth;
573 aiov[0].iov_len = sizeof(struct ktr_header);
574 auio.uio_resid = sizeof(struct ktr_header);
575 auio.uio_iovcnt = 1;
576 auio.uio_procp = (struct proc *)0;
577 if (kth->ktr_len > 0) {
578 auio.uio_iovcnt++;
579 aiov[1].iov_base = kth->ktr_buf;
580 aiov[1].iov_len = kth->ktr_len;
581 auio.uio_resid += kth->ktr_len;
582 }
583
584 FILE_USE(fp);
585
586 tries = 0;
587 do {
588 error = (*fp->f_ops->fo_write)(fp, &fp->f_offset, &auio,
589 fp->f_cred, FOF_UPDATE_OFFSET);
590 tries++;
591 if (error == EWOULDBLOCK)
592 yield();
593 } while ((error == EWOULDBLOCK) && (tries < 3));
594 FILE_UNUSE(fp, NULL);
595
596 if (__predict_true(error == 0))
597 return (0);
598 /*
599 * If error encountered, give up tracing on this vnode. Don't report
600 * EPIPE as this can easily happen with fktrace()/ktruss.
601 */
602 if (error != EPIPE)
603 log(LOG_NOTICE,
604 "ktrace write failed, errno %d, tracing stopped\n",
605 error);
606 proclist_lock_read();
607 for (p = LIST_FIRST(&allproc); p != NULL; p = LIST_NEXT(p, p_list)) {
608 if (p->p_tracep == fp)
609 ktrderef(p);
610 }
611 proclist_unlock_read();
612
613 return (error);
614 }
615
616 /*
617 * Return true if caller has permission to set the ktracing state
618 * of target. Essentially, the target can't possess any
619 * more permissions than the caller. KTRFAC_ROOT signifies that
620 * root previously set the tracing status on the target process, and
621 * so, only root may further change it.
622 *
623 * TODO: check groups. use caller effective gid.
624 */
625 int
626 ktrcanset(callp, targetp)
627 struct proc *callp, *targetp;
628 {
629 struct pcred *caller = callp->p_cred;
630 struct pcred *target = targetp->p_cred;
631
632 if ((caller->pc_ucred->cr_uid == target->p_ruid &&
633 target->p_ruid == target->p_svuid &&
634 caller->p_rgid == target->p_rgid && /* XXX */
635 target->p_rgid == target->p_svgid &&
636 (targetp->p_traceflag & KTRFAC_ROOT) == 0) ||
637 caller->pc_ucred->cr_uid == 0)
638 return (1);
639
640 return (0);
641 }
642
643 #endif
644