136359Smarc /*
263174Sbostic * Copyright (c) 1989, 1993
363174Sbostic * The Regents of the University of California. All rights reserved.
436359Smarc *
544436Sbostic * %sccs.include.redist.c%
636359Smarc *
7*69409Smckusick * @(#)kern_ktrace.c 8.5 (Berkeley) 05/14/95
836359Smarc */
936359Smarc
1036359Smarc #ifdef KTRACE
1136359Smarc
1256517Sbostic #include <sys/param.h>
1368329Scgd #include <sys/systm.h>
1456517Sbostic #include <sys/proc.h>
1556517Sbostic #include <sys/file.h>
1656517Sbostic #include <sys/namei.h>
1756517Sbostic #include <sys/vnode.h>
1856517Sbostic #include <sys/ktrace.h>
1956517Sbostic #include <sys/malloc.h>
2056517Sbostic #include <sys/syslog.h>
2136359Smarc
2268329Scgd #include <sys/mount.h>
2368329Scgd #include <sys/syscallargs.h>
2468329Scgd
2536359Smarc struct ktr_header *
ktrgetheader(type)2636359Smarc ktrgetheader(type)
2760514Storek int type;
2836359Smarc {
2936359Smarc register struct ktr_header *kth;
3048017Smckusick struct proc *p = curproc; /* XXX */
3136359Smarc
3236359Smarc MALLOC(kth, struct ktr_header *, sizeof (struct ktr_header),
3336359Smarc M_TEMP, M_WAITOK);
3436359Smarc kth->ktr_type = type;
3537593Smarc microtime(&kth->ktr_time);
3647548Skarels kth->ktr_pid = p->p_pid;
3747548Skarels bcopy(p->p_comm, kth->ktr_comm, MAXCOMLEN);
3836359Smarc return (kth);
3936359Smarc }
4036359Smarc
4168329Scgd void
ktrsyscall(vp,code,argsize,args)4268329Scgd ktrsyscall(vp, code, argsize, args)
4337728Smckusick struct vnode *vp;
4468329Scgd int code, argsize;
4568329Scgd register_t args[];
4636359Smarc {
4753012Smarc struct ktr_header *kth;
4836359Smarc struct ktr_syscall *ktp;
4968329Scgd register len = sizeof(struct ktr_syscall) + argsize;
5053012Smarc struct proc *p = curproc; /* XXX */
5168329Scgd register_t *argp;
5268329Scgd int i;
5336359Smarc
5453012Smarc p->p_traceflag |= KTRFAC_ACTIVE;
5553012Smarc kth = ktrgetheader(KTR_SYSCALL);
5636359Smarc MALLOC(ktp, struct ktr_syscall *, len, M_TEMP, M_WAITOK);
5736359Smarc ktp->ktr_code = code;
5868329Scgd ktp->ktr_argsize = argsize;
5968329Scgd argp = (register_t *)((char *)ktp + sizeof(struct ktr_syscall));
6068329Scgd for (i = 0; i < (argsize / sizeof *argp); i++)
6143444Smckusick *argp++ = args[i];
6236359Smarc kth->ktr_buf = (caddr_t)ktp;
6336359Smarc kth->ktr_len = len;
6437728Smckusick ktrwrite(vp, kth);
6536359Smarc FREE(ktp, M_TEMP);
6636359Smarc FREE(kth, M_TEMP);
6753012Smarc p->p_traceflag &= ~KTRFAC_ACTIVE;
6836359Smarc }
6936359Smarc
7068329Scgd void
ktrsysret(vp,code,error,retval)7143444Smckusick ktrsysret(vp, code, error, retval)
7237728Smckusick struct vnode *vp;
7343444Smckusick int code, error, retval;
7436359Smarc {
7553012Smarc struct ktr_header *kth;
7640805Smarc struct ktr_sysret ktp;
7753012Smarc struct proc *p = curproc; /* XXX */
7836359Smarc
7953012Smarc p->p_traceflag |= KTRFAC_ACTIVE;
8053012Smarc kth = ktrgetheader(KTR_SYSRET);
8140805Smarc ktp.ktr_code = code;
8243444Smckusick ktp.ktr_error = error;
8343444Smckusick ktp.ktr_retval = retval; /* what about val2 ? */
8436359Smarc
8540805Smarc kth->ktr_buf = (caddr_t)&ktp;
8636359Smarc kth->ktr_len = sizeof(struct ktr_sysret);
8736359Smarc
8837728Smckusick ktrwrite(vp, kth);
8936359Smarc FREE(kth, M_TEMP);
9053012Smarc p->p_traceflag &= ~KTRFAC_ACTIVE;
9136359Smarc }
9236359Smarc
9368329Scgd void
ktrnamei(vp,path)9437728Smckusick ktrnamei(vp, path)
9537728Smckusick struct vnode *vp;
9636359Smarc char *path;
9736359Smarc {
9853012Smarc struct ktr_header *kth;
9953012Smarc struct proc *p = curproc; /* XXX */
10036359Smarc
10153012Smarc p->p_traceflag |= KTRFAC_ACTIVE;
10253012Smarc kth = ktrgetheader(KTR_NAMEI);
10336359Smarc kth->ktr_len = strlen(path);
10436359Smarc kth->ktr_buf = path;
10536359Smarc
10637728Smckusick ktrwrite(vp, kth);
10736359Smarc FREE(kth, M_TEMP);
10853012Smarc p->p_traceflag &= ~KTRFAC_ACTIVE;
10936359Smarc }
11036359Smarc
11168329Scgd void
ktrgenio(vp,fd,rw,iov,len,error)11243444Smckusick ktrgenio(vp, fd, rw, iov, len, error)
11337728Smckusick struct vnode *vp;
11443444Smckusick int fd;
11537593Smarc enum uio_rw rw;
11637593Smarc register struct iovec *iov;
11760514Storek int len, error;
11837593Smarc {
11953012Smarc struct ktr_header *kth;
12037593Smarc register struct ktr_genio *ktp;
12137593Smarc register caddr_t cp;
12237593Smarc register int resid = len, cnt;
12353012Smarc struct proc *p = curproc; /* XXX */
12437593Smarc
12546424Smarc if (error)
12637593Smarc return;
12753012Smarc p->p_traceflag |= KTRFAC_ACTIVE;
12853012Smarc kth = ktrgetheader(KTR_GENIO);
12937593Smarc MALLOC(ktp, struct ktr_genio *, sizeof(struct ktr_genio) + len,
13037593Smarc M_TEMP, M_WAITOK);
13137593Smarc ktp->ktr_fd = fd;
13237593Smarc ktp->ktr_rw = rw;
13337593Smarc cp = (caddr_t)((char *)ktp + sizeof (struct ktr_genio));
13437593Smarc while (resid > 0) {
13537593Smarc if ((cnt = iov->iov_len) > resid)
13637593Smarc cnt = resid;
13741573Smckusick if (copyin(iov->iov_base, cp, (unsigned)cnt))
13837593Smarc goto done;
13937593Smarc cp += cnt;
14037593Smarc resid -= cnt;
14137593Smarc iov++;
14237593Smarc }
14337593Smarc kth->ktr_buf = (caddr_t)ktp;
14437593Smarc kth->ktr_len = sizeof (struct ktr_genio) + len;
14537593Smarc
14637728Smckusick ktrwrite(vp, kth);
14737593Smarc done:
14837593Smarc FREE(kth, M_TEMP);
14937593Smarc FREE(ktp, M_TEMP);
15053012Smarc p->p_traceflag &= ~KTRFAC_ACTIVE;
15137593Smarc }
15237593Smarc
15368329Scgd void
ktrpsig(vp,sig,action,mask,code)15440805Smarc ktrpsig(vp, sig, action, mask, code)
15560514Storek struct vnode *vp;
15660514Storek int sig;
15760514Storek sig_t action;
15860514Storek int mask, code;
15940805Smarc {
16053012Smarc struct ktr_header *kth;
16140805Smarc struct ktr_psig kp;
16253012Smarc struct proc *p = curproc; /* XXX */
16340805Smarc
16453012Smarc p->p_traceflag |= KTRFAC_ACTIVE;
16553012Smarc kth = ktrgetheader(KTR_PSIG);
16640805Smarc kp.signo = (char)sig;
16740805Smarc kp.action = action;
16840805Smarc kp.mask = mask;
16940805Smarc kp.code = code;
17040805Smarc kth->ktr_buf = (caddr_t)&kp;
17140805Smarc kth->ktr_len = sizeof (struct ktr_psig);
17240805Smarc
17340805Smarc ktrwrite(vp, kth);
17440805Smarc FREE(kth, M_TEMP);
17553012Smarc p->p_traceflag &= ~KTRFAC_ACTIVE;
17640805Smarc }
17740805Smarc
17868329Scgd void
ktrcsw(vp,out,user)17953012Smarc ktrcsw(vp, out, user)
18060514Storek struct vnode *vp;
18160514Storek int out, user;
18253012Smarc {
18353012Smarc struct ktr_header *kth;
18453012Smarc struct ktr_csw kc;
18553012Smarc struct proc *p = curproc; /* XXX */
18653012Smarc
18753012Smarc p->p_traceflag |= KTRFAC_ACTIVE;
18853012Smarc kth = ktrgetheader(KTR_CSW);
18953012Smarc kc.out = out;
19053012Smarc kc.user = user;
19153012Smarc kth->ktr_buf = (caddr_t)&kc;
19253012Smarc kth->ktr_len = sizeof (struct ktr_csw);
19353012Smarc
19453012Smarc ktrwrite(vp, kth);
19553012Smarc FREE(kth, M_TEMP);
19653012Smarc p->p_traceflag &= ~KTRFAC_ACTIVE;
19753012Smarc }
19853012Smarc
19940805Smarc /* Interface and common routines */
20040805Smarc
20136359Smarc /*
20236359Smarc * ktrace system call
20336359Smarc */
20443444Smckusick /* ARGSUSED */
20568329Scgd int
ktrace(curp,uap,retval)20643444Smckusick ktrace(curp, uap, retval)
20743444Smckusick struct proc *curp;
20868329Scgd register struct ktrace_args /* {
20968329Scgd syscallarg(char *) fname;
21068329Scgd syscallarg(int) ops;
21168329Scgd syscallarg(int) facs;
21268329Scgd syscallarg(int) pid;
21368329Scgd } */ *uap;
21468329Scgd register_t *retval;
21543444Smckusick {
21637728Smckusick register struct vnode *vp = NULL;
21736359Smarc register struct proc *p;
21836359Smarc struct pgrp *pg;
21968329Scgd int facs = SCARG(uap, facs) & ~KTRFAC_ROOT;
22068329Scgd int ops = KTROP(SCARG(uap, ops));
22168329Scgd int descend = SCARG(uap, ops) & KTRFLAG_DESCEND;
22246424Smarc int ret = 0;
22343444Smckusick int error = 0;
22447548Skarels struct nameidata nd;
22536359Smarc
22653012Smarc curp->p_traceflag |= KTRFAC_ACTIVE;
22736359Smarc if (ops != KTROP_CLEAR) {
22836359Smarc /*
22936359Smarc * an operation which requires a file argument.
23036359Smarc */
23168329Scgd NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, fname),
23268329Scgd curp);
23353012Smarc if (error = vn_open(&nd, FREAD|FWRITE, 0)) {
23453012Smarc curp->p_traceflag &= ~KTRFAC_ACTIVE;
23544404Skarels return (error);
23653012Smarc }
23747548Skarels vp = nd.ni_vp;
238*69409Smckusick VOP_UNLOCK(vp, 0, p);
23937728Smckusick if (vp->v_type != VREG) {
24050106Smckusick (void) vn_close(vp, FREAD|FWRITE, curp->p_ucred, curp);
24153012Smarc curp->p_traceflag &= ~KTRFAC_ACTIVE;
24244404Skarels return (EACCES);
24336359Smarc }
24436359Smarc }
24536359Smarc /*
24636359Smarc * Clear all uses of the tracefile
24736359Smarc */
24836359Smarc if (ops == KTROP_CLEARFILE) {
24967732Smckusick for (p = allproc.lh_first; p != 0; p = p->p_list.le_next) {
25037728Smckusick if (p->p_tracep == vp) {
25146424Smarc if (ktrcanset(curp, p)) {
25246424Smarc p->p_tracep = NULL;
25346424Smarc p->p_traceflag = 0;
25450106Smckusick (void) vn_close(vp, FREAD|FWRITE,
25550106Smckusick p->p_ucred, p);
25646424Smarc } else
25746424Smarc error = EPERM;
25836359Smarc }
25936359Smarc }
26036359Smarc goto done;
26136359Smarc }
26236359Smarc /*
26346424Smarc * need something to (un)trace (XXX - why is this here?)
26436359Smarc */
26536359Smarc if (!facs) {
26643444Smckusick error = EINVAL;
26736359Smarc goto done;
26836359Smarc }
26940805Smarc /*
27046424Smarc * do it
27140805Smarc */
27268329Scgd if (SCARG(uap, pid) < 0) {
27346424Smarc /*
27446424Smarc * by process group
27546424Smarc */
27668329Scgd pg = pgfind(-SCARG(uap, pid));
27736359Smarc if (pg == NULL) {
27843444Smckusick error = ESRCH;
27936359Smarc goto done;
28036359Smarc }
28167732Smckusick for (p = pg->pg_members.lh_first; p != 0; p = p->p_pglist.le_next)
28246424Smarc if (descend)
28346424Smarc ret |= ktrsetchildren(curp, p, ops, facs, vp);
28436359Smarc else
28546424Smarc ret |= ktrops(curp, p, ops, facs, vp);
28636359Smarc
28736359Smarc } else {
28846424Smarc /*
28946424Smarc * by pid
29046424Smarc */
29168329Scgd p = pfind(SCARG(uap, pid));
29236359Smarc if (p == NULL) {
29343444Smckusick error = ESRCH;
29436359Smarc goto done;
29536359Smarc }
29646424Smarc if (descend)
29746424Smarc ret |= ktrsetchildren(curp, p, ops, facs, vp);
29836359Smarc else
29946424Smarc ret |= ktrops(curp, p, ops, facs, vp);
30036359Smarc }
30137593Smarc if (!ret)
30243444Smckusick error = EPERM;
30336359Smarc done:
30437728Smckusick if (vp != NULL)
30550106Smckusick (void) vn_close(vp, FWRITE, curp->p_ucred, curp);
30653012Smarc curp->p_traceflag &= ~KTRFAC_ACTIVE;
30744404Skarels return (error);
30836359Smarc }
30936359Smarc
31060514Storek int
ktrops(curp,p,ops,facs,vp)31146424Smarc ktrops(curp, p, ops, facs, vp)
31260514Storek struct proc *p, *curp;
31360514Storek int ops, facs;
31437728Smckusick struct vnode *vp;
31536359Smarc {
31637593Smarc
31746424Smarc if (!ktrcanset(curp, p))
31844404Skarels return (0);
31936359Smarc if (ops == KTROP_SET) {
32040805Smarc if (p->p_tracep != vp) {
32136359Smarc /*
32236359Smarc * if trace file already in use, relinquish
32336359Smarc */
32436359Smarc if (p->p_tracep != NULL)
32537728Smckusick vrele(p->p_tracep);
32638423Smarc VREF(vp);
32737728Smckusick p->p_tracep = vp;
32836359Smarc }
32936359Smarc p->p_traceflag |= facs;
33047548Skarels if (curp->p_ucred->cr_uid == 0)
33146424Smarc p->p_traceflag |= KTRFAC_ROOT;
33236359Smarc } else {
33336359Smarc /* KTROP_CLEAR */
33446424Smarc if (((p->p_traceflag &= ~facs) & KTRFAC_MASK) == 0) {
33540805Smarc /* no more tracing */
33640805Smarc p->p_traceflag = 0;
33736359Smarc if (p->p_tracep != NULL) {
33837728Smckusick vrele(p->p_tracep);
33936359Smarc p->p_tracep = NULL;
34036359Smarc }
34136359Smarc }
34236359Smarc }
34337593Smarc
34446424Smarc return (1);
34536359Smarc }
34637593Smarc
34746424Smarc ktrsetchildren(curp, top, ops, facs, vp)
34846424Smarc struct proc *curp, *top;
34960514Storek int ops, facs;
35037728Smckusick struct vnode *vp;
35136359Smarc {
35236359Smarc register struct proc *p;
35337593Smarc register int ret = 0;
35436359Smarc
35536359Smarc p = top;
35636359Smarc for (;;) {
35746424Smarc ret |= ktrops(curp, p, ops, facs, vp);
35836359Smarc /*
35936359Smarc * If this process has children, descend to them next,
36036359Smarc * otherwise do any siblings, and if done with this level,
36136359Smarc * follow back up the tree (but not past top).
36236359Smarc */
36367732Smckusick if (p->p_children.lh_first)
36467732Smckusick p = p->p_children.lh_first;
36536359Smarc else for (;;) {
36636359Smarc if (p == top)
36746424Smarc return (ret);
36867732Smckusick if (p->p_sibling.le_next) {
36967732Smckusick p = p->p_sibling.le_next;
37036359Smarc break;
37136359Smarc }
37267732Smckusick p = p->p_pptr;
37336359Smarc }
37436359Smarc }
37537593Smarc /*NOTREACHED*/
37636359Smarc }
37736359Smarc
37837728Smckusick ktrwrite(vp, kth)
37937728Smckusick struct vnode *vp;
38037728Smckusick register struct ktr_header *kth;
38136359Smarc {
38237728Smckusick struct uio auio;
38337728Smckusick struct iovec aiov[2];
38448017Smckusick register struct proc *p = curproc; /* XXX */
38539581Smckusick int error;
38637728Smckusick
38737728Smckusick if (vp == NULL)
38837593Smarc return;
38937728Smckusick auio.uio_iov = &aiov[0];
39037728Smckusick auio.uio_offset = 0;
39137728Smckusick auio.uio_segflg = UIO_SYSSPACE;
39237728Smckusick auio.uio_rw = UIO_WRITE;
39337728Smckusick aiov[0].iov_base = (caddr_t)kth;
39437728Smckusick aiov[0].iov_len = sizeof(struct ktr_header);
39537728Smckusick auio.uio_resid = sizeof(struct ktr_header);
39637728Smckusick auio.uio_iovcnt = 1;
39748017Smckusick auio.uio_procp = (struct proc *)0;
39836359Smarc if (kth->ktr_len > 0) {
39937728Smckusick auio.uio_iovcnt++;
40037728Smckusick aiov[1].iov_base = kth->ktr_buf;
40137728Smckusick aiov[1].iov_len = kth->ktr_len;
40237728Smckusick auio.uio_resid += kth->ktr_len;
40336359Smarc }
404*69409Smckusick vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
40548017Smckusick error = VOP_WRITE(vp, &auio, IO_UNIT|IO_APPEND, p->p_ucred);
406*69409Smckusick VOP_UNLOCK(vp, 0, p);
40741573Smckusick if (!error)
40841573Smckusick return;
40941573Smckusick /*
41041573Smckusick * If error encountered, give up tracing on this vnode.
41141573Smckusick */
41247548Skarels log(LOG_NOTICE, "ktrace write failed, errno %d, tracing stopped\n",
41347548Skarels error);
41467732Smckusick for (p = allproc.lh_first; p != 0; p = p->p_list.le_next) {
41541573Smckusick if (p->p_tracep == vp) {
41641573Smckusick p->p_tracep = NULL;
41741573Smckusick p->p_traceflag = 0;
41841573Smckusick vrele(vp);
41941573Smckusick }
42041573Smckusick }
42136359Smarc }
42246424Smarc
42346424Smarc /*
42446424Smarc * Return true if caller has permission to set the ktracing state
42546424Smarc * of target. Essentially, the target can't possess any
42646424Smarc * more permissions than the caller. KTRFAC_ROOT signifies that
42746424Smarc * root previously set the tracing status on the target process, and
42846424Smarc * so, only root may further change it.
42946424Smarc *
43047548Skarels * TODO: check groups. use caller effective gid.
43146424Smarc */
43247548Skarels ktrcanset(callp, targetp)
43347548Skarels struct proc *callp, *targetp;
43446424Smarc {
43547548Skarels register struct pcred *caller = callp->p_cred;
43647548Skarels register struct pcred *target = targetp->p_cred;
43747548Skarels
43847548Skarels if ((caller->pc_ucred->cr_uid == target->p_ruid &&
43946424Smarc target->p_ruid == target->p_svuid &&
44046424Smarc caller->p_rgid == target->p_rgid && /* XXX */
44146424Smarc target->p_rgid == target->p_svgid &&
44247548Skarels (targetp->p_traceflag & KTRFAC_ROOT) == 0) ||
44347548Skarels caller->pc_ucred->cr_uid == 0)
44446424Smarc return (1);
44546424Smarc
44646424Smarc return (0);
44746424Smarc }
44846424Smarc
44936359Smarc #endif
450