]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/kern/kern_ktrace.c
This commit was generated by cvs2svn to compensate for changes in r95419,
[FreeBSD/FreeBSD.git] / sys / kern / kern_ktrace.c
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$
35  */
36
37 #include "opt_ktrace.h"
38
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/lock.h>
42 #include <sys/mutex.h>
43 #include <sys/sysproto.h>
44 #include <sys/kernel.h>
45 #include <sys/proc.h>
46 #include <sys/fcntl.h>
47 #include <sys/namei.h>
48 #include <sys/vnode.h>
49 #include <sys/ktrace.h>
50 #include <sys/malloc.h>
51 #include <sys/sx.h>
52 #include <sys/syslog.h>
53 #include <sys/jail.h>
54
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 thread *, struct proc *);
61 static int ktrsetchildren(struct thread *, struct proc *, int, int, struct vnode *);
62 static int ktrops(struct thread *, struct proc *, int, int, struct vnode *);
63
64
65 static struct ktr_header *
66 ktrgetheader(type)
67         int type;
68 {
69         register 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 /*
82  * MPSAFE
83  */
84 void
85 ktrsyscall(vp, code, narg, args)
86         struct vnode *vp;
87         int code, narg;
88         register_t args[];
89 {
90         struct  ktr_header *kth;
91         struct  ktr_syscall *ktp;
92         register int len = offsetof(struct ktr_syscall, ktr_args) +
93             (narg * sizeof(register_t));
94         struct proc *p = curproc;       /* XXX */
95         register_t *argp;
96         int i;
97
98         mtx_lock(&Giant);
99         p->p_traceflag |= KTRFAC_ACTIVE;
100         kth = ktrgetheader(KTR_SYSCALL);
101         MALLOC(ktp, struct ktr_syscall *, len, M_KTRACE, M_WAITOK);
102         ktp->ktr_code = code;
103         ktp->ktr_narg = narg;
104         argp = &ktp->ktr_args[0];
105         for (i = 0; i < narg; i++)
106                 *argp++ = args[i];
107         kth->ktr_buffer = (caddr_t)ktp;
108         kth->ktr_len = len;
109         ktrwrite(vp, kth, NULL);
110         FREE(ktp, M_KTRACE);
111         FREE(kth, M_KTRACE);
112         p->p_traceflag &= ~KTRFAC_ACTIVE;
113         mtx_unlock(&Giant);
114 }
115
116 /*
117  * MPSAFE
118  */
119 void
120 ktrsysret(vp, code, error, retval)
121         struct vnode *vp;
122         int code, error;
123         register_t retval;
124 {
125         struct ktr_header *kth;
126         struct ktr_sysret ktp;
127         struct proc *p = curproc;       /* XXX */
128
129         mtx_lock(&Giant);
130         p->p_traceflag |= KTRFAC_ACTIVE;
131         kth = ktrgetheader(KTR_SYSRET);
132         ktp.ktr_code = code;
133         ktp.ktr_error = error;
134         ktp.ktr_retval = retval;                /* what about val2 ? */
135
136         kth->ktr_buffer = (caddr_t)&ktp;
137         kth->ktr_len = sizeof(struct ktr_sysret);
138
139         ktrwrite(vp, kth, NULL);
140         FREE(kth, M_KTRACE);
141         p->p_traceflag &= ~KTRFAC_ACTIVE;
142         mtx_unlock(&Giant);
143 }
144
145 void
146 ktrnamei(vp, path)
147         struct vnode *vp;
148         char *path;
149 {
150         struct ktr_header *kth;
151         struct proc *p = curproc;       /* XXX */
152
153         /*
154          * don't let p_tracep get ripped out from under us
155          */
156         if (vp)
157                 VREF(vp);
158         p->p_traceflag |= KTRFAC_ACTIVE;
159         kth = ktrgetheader(KTR_NAMEI);
160         kth->ktr_len = strlen(path);
161         kth->ktr_buffer = path;
162
163         ktrwrite(vp, kth, NULL);
164         if (vp)
165                 vrele(vp);
166         FREE(kth, M_KTRACE);
167         p->p_traceflag &= ~KTRFAC_ACTIVE;
168 }
169
170 void
171 ktrgenio(vp, fd, rw, uio, error)
172         struct vnode *vp;
173         int fd;
174         enum uio_rw rw;
175         struct uio *uio;
176         int error;
177 {
178         struct ktr_header *kth;
179         struct ktr_genio ktg;
180         struct proc *p = curproc;       /* XXX */
181
182         if (error)
183                 return;
184
185         mtx_lock(&Giant);
186         /*
187          * don't let p_tracep get ripped out from under us
188          */
189         if (vp)
190                 VREF(vp);
191         p->p_traceflag |= KTRFAC_ACTIVE;
192         kth = ktrgetheader(KTR_GENIO);
193         ktg.ktr_fd = fd;
194         ktg.ktr_rw = rw;
195         kth->ktr_buffer = (caddr_t)&ktg;
196         kth->ktr_len = sizeof(struct ktr_genio);
197         uio->uio_offset = 0;
198         uio->uio_rw = UIO_WRITE;
199
200         ktrwrite(vp, kth, uio);
201         if (vp)
202                 vrele(vp);
203         FREE(kth, M_KTRACE);
204         p->p_traceflag &= ~KTRFAC_ACTIVE;
205         mtx_unlock(&Giant);
206 }
207
208 void
209 ktrpsig(vp, sig, action, mask, code)
210         struct vnode *vp;
211         int sig;
212         sig_t action;
213         sigset_t *mask;
214         int code;
215 {
216         struct ktr_header *kth;
217         struct ktr_psig kp;
218         struct proc *p = curproc;       /* XXX */
219
220         /*
221          * don't let vp get ripped out from under us
222          */
223         if (vp)
224                 VREF(vp);
225         p->p_traceflag |= KTRFAC_ACTIVE;
226         kth = ktrgetheader(KTR_PSIG);
227         kp.signo = (char)sig;
228         kp.action = action;
229         kp.mask = *mask;
230         kp.code = code;
231         kth->ktr_buffer = (caddr_t)&kp;
232         kth->ktr_len = sizeof (struct ktr_psig);
233
234         ktrwrite(vp, kth, NULL);
235         if (vp)
236                 vrele(vp);
237         FREE(kth, M_KTRACE);
238         p->p_traceflag &= ~KTRFAC_ACTIVE;
239 }
240
241 void
242 ktrcsw(vp, out, user)
243         struct vnode *vp;
244         int out, user;
245 {
246         struct ktr_header *kth;
247         struct  ktr_csw kc;
248         struct proc *p = curproc;       /* XXX */
249
250         /*
251          * don't let vp get ripped out from under us
252          */
253         if (vp)
254                 VREF(vp);
255         p->p_traceflag |= KTRFAC_ACTIVE;
256         kth = ktrgetheader(KTR_CSW);
257         kc.out = out;
258         kc.user = user;
259         kth->ktr_buffer = (caddr_t)&kc;
260         kth->ktr_len = sizeof (struct ktr_csw);
261
262         ktrwrite(vp, kth, NULL);
263         if (vp)
264                 vrele(vp);
265         FREE(kth, M_KTRACE);
266         p->p_traceflag &= ~KTRFAC_ACTIVE;
267 }
268 #endif
269
270 /* Interface and common routines */
271
272 /*
273  * ktrace system call
274  */
275 #ifndef _SYS_SYSPROTO_H_
276 struct ktrace_args {
277         char    *fname;
278         int     ops;
279         int     facs;
280         int     pid;
281 };
282 #endif
283 /* ARGSUSED */
284 int
285 ktrace(td, uap)
286         struct thread *td;
287         register struct ktrace_args *uap;
288 {
289 #ifdef KTRACE
290         struct proc *curp = td->td_proc;
291         register struct vnode *vp = NULL;
292         register struct proc *p;
293         struct pgrp *pg;
294         int facs = uap->facs & ~KTRFAC_ROOT;
295         int ops = KTROP(uap->ops);
296         int descend = uap->ops & KTRFLAG_DESCEND;
297         int ret = 0;
298         int flags, error = 0;
299         struct nameidata nd;
300
301         curp->p_traceflag |= KTRFAC_ACTIVE;
302         if (ops != KTROP_CLEAR) {
303                 /*
304                  * an operation which requires a file argument.
305                  */
306                 NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, uap->fname, td);
307                 flags = FREAD | FWRITE | O_NOFOLLOW;
308                 error = vn_open(&nd, &flags, 0);
309                 if (error) {
310                         curp->p_traceflag &= ~KTRFAC_ACTIVE;
311                         return (error);
312                 }
313                 NDFREE(&nd, NDF_ONLY_PNBUF);
314                 vp = nd.ni_vp;
315                 VOP_UNLOCK(vp, 0, td);
316                 if (vp->v_type != VREG) {
317                         (void) vn_close(vp, FREAD|FWRITE, td->td_ucred, td);
318                         curp->p_traceflag &= ~KTRFAC_ACTIVE;
319                         return (EACCES);
320                 }
321         }
322         /*
323          * Clear all uses of the tracefile.
324          */
325         if (ops == KTROP_CLEARFILE) {
326                 sx_slock(&allproc_lock);
327                 LIST_FOREACH(p, &allproc, p_list) {
328                         PROC_LOCK(p);
329                         if (p->p_tracep == vp) {
330                                 if (ktrcanset(td, p) && p->p_tracep == vp) {
331                                         p->p_tracep = NULL;
332                                         p->p_traceflag = 0;
333                                         PROC_UNLOCK(p);
334                                         (void) vn_close(vp, FREAD|FWRITE,
335                                                 td->td_ucred, td);
336                                 } else {
337                                         PROC_UNLOCK(p);
338                                         error = EPERM;
339                                 }
340                         } else
341                                 PROC_UNLOCK(p);
342                 }
343                 sx_sunlock(&allproc_lock);
344                 goto done;
345         }
346         /*
347          * need something to (un)trace (XXX - why is this here?)
348          */
349         if (!facs) {
350                 error = EINVAL;
351                 goto done;
352         }
353         /*
354          * do it
355          */
356         if (uap->pid < 0) {
357                 /*
358                  * by process group
359                  */
360                 sx_slock(&proctree_lock);
361                 pg = pgfind(-uap->pid);
362                 if (pg == NULL) {
363                         sx_sunlock(&proctree_lock);
364                         error = ESRCH;
365                         goto done;
366                 }
367                 /*
368                  * ktrops() may call vrele(). Lock pg_members
369                  * by the proctree_lock rather than pg_mtx.
370                  */
371                 PGRP_UNLOCK(pg);
372                 LIST_FOREACH(p, &pg->pg_members, p_pglist)
373                         if (descend)
374                                 ret |= ktrsetchildren(td, p, ops, facs, vp);
375                         else
376                                 ret |= ktrops(td, p, ops, facs, vp);
377                 sx_sunlock(&proctree_lock);
378         } else {
379                 /*
380                  * by pid
381                  */
382                 p = pfind(uap->pid);
383                 if (p == NULL) {
384                         error = ESRCH;
385                         goto done;
386                 }
387                 PROC_UNLOCK(p);
388                 /* XXX: UNLOCK above has a race */
389                 if (descend)
390                         ret |= ktrsetchildren(td, p, ops, facs, vp);
391                 else
392                         ret |= ktrops(td, p, ops, facs, vp);
393         }
394         if (!ret)
395                 error = EPERM;
396 done:
397         if (vp != NULL)
398                 (void) vn_close(vp, FWRITE, td->td_ucred, td);
399         curp->p_traceflag &= ~KTRFAC_ACTIVE;
400         return (error);
401 #else
402         return ENOSYS;
403 #endif
404 }
405
406 /*
407  * utrace system call
408  */
409 /* ARGSUSED */
410 int
411 utrace(td, uap)
412         struct thread *td;
413         register struct utrace_args *uap;
414 {
415
416 #ifdef KTRACE
417         struct ktr_header *kth;
418         struct proc *p = curproc;       /* XXX */
419         struct vnode *vp;
420         register caddr_t cp;
421
422         if (!KTRPOINT(p, KTR_USER))
423                 return (0);
424         if (uap->len > KTR_USER_MAXLEN)
425                 return (EINVAL);
426         p->p_traceflag |= KTRFAC_ACTIVE;
427         if ((vp = p->p_tracep) != NULL)
428                 VREF(vp);
429         kth = ktrgetheader(KTR_USER);
430         MALLOC(cp, caddr_t, uap->len, M_KTRACE, M_WAITOK);
431         if (!copyin(uap->addr, cp, uap->len)) {
432                 kth->ktr_buffer = cp;
433                 kth->ktr_len = uap->len;
434                 ktrwrite(vp, kth, NULL);
435         }
436         if (vp)
437                 vrele(vp);
438         FREE(kth, M_KTRACE);
439         FREE(cp, M_KTRACE);
440         p->p_traceflag &= ~KTRFAC_ACTIVE;
441
442         return (0);
443 #else
444         return (ENOSYS);
445 #endif
446 }
447
448 #ifdef KTRACE
449 static int
450 ktrops(td, p, ops, facs, vp)
451         struct thread *td;
452         struct proc *p;
453         int ops, facs;
454         struct vnode *vp;
455 {
456         struct vnode *vtmp = NULL, *newvp = NULL;
457
458         PROC_LOCK(p);
459         if (!ktrcanset(td, p)) {
460                 PROC_UNLOCK(p);
461                 return (0);
462         }
463         if (ops == KTROP_SET) {
464                 if (p->p_tracep != vp) {
465                         struct vnode *vtmp;
466
467                         /*
468                          * if trace file already in use, relinquish below
469                          */
470                         newvp = vp;
471                         vtmp = p->p_tracep;
472                         p->p_tracep = NULL;
473                 }
474                 p->p_traceflag |= facs;
475                 if (td->td_ucred->cr_uid == 0)
476                         p->p_traceflag |= KTRFAC_ROOT;
477         } else {
478                 /* KTROP_CLEAR */
479                 if (((p->p_traceflag &= ~facs) & KTRFAC_MASK) == 0) {
480                         struct vnode *vtmp;
481
482                         /* no more tracing */
483                         p->p_traceflag = 0;
484                         vtmp = p->p_tracep;
485                         p->p_tracep = NULL;
486                 }
487         }
488         PROC_UNLOCK(p);
489
490         /* Release old trace file if requested. */
491         if (vtmp != NULL)
492                 vrele(vtmp);
493
494         /* Setup new trace file if requested. */
495         /*
496          * XXX: Doing this before the PROC_UNLOCK above would result in
497          * fewer lock operations but would break old behavior where the
498          * above vrele() would not be traced when changing trace files.
499          */
500         if (newvp != NULL) {
501                 VREF(newvp);
502                 PROC_LOCK(p);
503                 p->p_tracep = newvp;
504                 PROC_UNLOCK(p);
505         }
506                         
507         return (1);
508 }
509
510 static int
511 ktrsetchildren(td, top, ops, facs, vp)
512         struct thread *td;
513         struct proc *top;
514         int ops, facs;
515         struct vnode *vp;
516 {
517         register struct proc *p;
518         register int ret = 0;
519
520         p = top;
521         sx_slock(&proctree_lock);
522         for (;;) {
523                 ret |= ktrops(td, p, ops, facs, vp);
524                 /*
525                  * If this process has children, descend to them next,
526                  * otherwise do any siblings, and if done with this level,
527                  * follow back up the tree (but not past top).
528                  */
529                 if (!LIST_EMPTY(&p->p_children))
530                         p = LIST_FIRST(&p->p_children);
531                 else for (;;) {
532                         if (p == top) {
533                                 sx_sunlock(&proctree_lock);
534                                 return (ret);
535                         }
536                         if (LIST_NEXT(p, p_sibling)) {
537                                 p = LIST_NEXT(p, p_sibling);
538                                 break;
539                         }
540                         p = p->p_pptr;
541                 }
542         }
543         /*NOTREACHED*/
544 }
545
546 static void
547 ktrwrite(vp, kth, uio)
548         struct vnode *vp;
549         register struct ktr_header *kth;
550         struct uio *uio;
551 {
552         struct uio auio;
553         struct iovec aiov[2];
554         struct thread *td = curthread;  /* XXX */
555         struct proc *p = td->td_proc;   /* XXX */
556         struct mount *mp;
557         int error;
558
559         if (vp == NULL)
560                 return;
561         auio.uio_iov = &aiov[0];
562         auio.uio_offset = 0;
563         auio.uio_segflg = UIO_SYSSPACE;
564         auio.uio_rw = UIO_WRITE;
565         aiov[0].iov_base = (caddr_t)kth;
566         aiov[0].iov_len = sizeof(struct ktr_header);
567         auio.uio_resid = sizeof(struct ktr_header);
568         auio.uio_iovcnt = 1;
569         auio.uio_td = curthread;
570         if (kth->ktr_len > 0) {
571                 auio.uio_iovcnt++;
572                 aiov[1].iov_base = kth->ktr_buffer;
573                 aiov[1].iov_len = kth->ktr_len;
574                 auio.uio_resid += kth->ktr_len;
575                 if (uio != NULL)
576                         kth->ktr_len += uio->uio_resid;
577         }
578         vn_start_write(vp, &mp, V_WAIT);
579         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
580         (void)VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE);
581         error = VOP_WRITE(vp, &auio, IO_UNIT | IO_APPEND, td->td_ucred);
582         if (error == 0 && uio != NULL) {
583                 (void)VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE);
584                 error = VOP_WRITE(vp, uio, IO_UNIT | IO_APPEND, td->td_ucred);
585         }
586         VOP_UNLOCK(vp, 0, td);
587         vn_finished_write(mp);
588         if (!error)
589                 return;
590         /*
591          * If error encountered, give up tracing on this vnode.  XXX what
592          * happens to the loop if vrele() blocks?
593          */
594         log(LOG_NOTICE, "ktrace write failed, errno %d, tracing stopped\n",
595             error);
596         sx_slock(&allproc_lock);
597         LIST_FOREACH(p, &allproc, p_list) {
598                 if (p->p_tracep == vp) {
599                         p->p_tracep = NULL;
600                         p->p_traceflag = 0;
601                         vrele(vp);
602                 }
603         }
604         sx_sunlock(&allproc_lock);
605 }
606
607 /*
608  * Return true if caller has permission to set the ktracing state
609  * of target.  Essentially, the target can't possess any
610  * more permissions than the caller.  KTRFAC_ROOT signifies that
611  * root previously set the tracing status on the target process, and
612  * so, only root may further change it.
613  */
614 static int
615 ktrcanset(td, targetp)
616         struct thread *td;
617         struct proc *targetp;
618 {
619
620         PROC_LOCK_ASSERT(targetp, MA_OWNED);
621         if (targetp->p_traceflag & KTRFAC_ROOT &&
622             suser_cred(td->td_ucred, PRISON_ROOT))
623                 return (0);
624
625         if (p_candebug(td->td_proc, targetp) != 0)
626                 return (0);
627
628         return (1);
629 }
630
631 #endif /* KTRACE */