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