ec_rxstart doesn't eists
[unix-history] / usr / src / sys / kern / kern_ktrace.c
index f4c1cf6..884cb4a 100644 (file)
@@ -2,68 +2,52 @@
  * Copyright (c) 1989 The Regents of the University of California.
  * All rights reserved.
  *
  * Copyright (c) 1989 The Regents of the University of California.
  * All rights reserved.
  *
- * Redistribution and use in source and binary forms are permitted
- * provided that the above copyright notice and this paragraph are
- * duplicated in all such forms and that any documentation,
- * advertising materials, and other materials related to such
- * distribution and use acknowledge that the software was developed
- * by the University of California, Berkeley.  The name of the
- * University may not be used to endorse or promote products derived
- * from this software without specific prior written permission.
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ * %sccs.include.redist.c%
  *
  *
- *     @(#)kern_ktrace.c       1.4 (Berkeley) %G%
+ *     @(#)kern_ktrace.c       7.15 (Berkeley) %G%
  */
 
 #ifdef KTRACE
 
 #include "param.h"
  */
 
 #ifdef KTRACE
 
 #include "param.h"
-#include "user.h"
 #include "proc.h"
 #include "file.h"
 #include "proc.h"
 #include "file.h"
+#include "namei.h"
 #include "vnode.h"
 #include "ktrace.h"
 #include "malloc.h"
 #include "vnode.h"
 #include "ktrace.h"
 #include "malloc.h"
-
-#include "syscalls.c"
-
-extern int nsysent;
-extern char *syscallnames[];
-
-int ktrace_nocheck = 1;
+#include "syslog.h"
 
 struct ktr_header *
 ktrgetheader(type)
 {
        register struct ktr_header *kth;
 
 struct ktr_header *
 ktrgetheader(type)
 {
        register struct ktr_header *kth;
+       struct proc *p = curproc;       /* XXX */
 
        MALLOC(kth, struct ktr_header *, sizeof (struct ktr_header), 
                M_TEMP, M_WAITOK);
        kth->ktr_type = type;
        microtime(&kth->ktr_time);
 
        MALLOC(kth, struct ktr_header *, sizeof (struct ktr_header), 
                M_TEMP, M_WAITOK);
        kth->ktr_type = type;
        microtime(&kth->ktr_time);
-       kth->ktr_pid = u.u_procp->p_pid;
-       bcopy(u.u_comm, kth->ktr_comm, MAXCOMLEN);
+       kth->ktr_pid = p->p_pid;
+       bcopy(p->p_comm, kth->ktr_comm, MAXCOMLEN);
        return (kth);
 }
 
        return (kth);
 }
 
-ktrsyscall(vp, code, narg)
+ktrsyscall(vp, code, narg, args)
        struct vnode *vp;
        struct vnode *vp;
+       int code, narg, args[];
 {
        struct  ktr_header *kth = ktrgetheader(KTR_SYSCALL);
        struct  ktr_syscall *ktp;
        register len = sizeof(struct ktr_syscall) + (narg * sizeof(int));
        int     *argp, i;
 
 {
        struct  ktr_header *kth = ktrgetheader(KTR_SYSCALL);
        struct  ktr_syscall *ktp;
        register len = sizeof(struct ktr_syscall) + (narg * sizeof(int));
        int     *argp, i;
 
-       if (kth == NULL)
-               return;
        MALLOC(ktp, struct ktr_syscall *, len, M_TEMP, M_WAITOK);
        ktp->ktr_code = code;
        ktp->ktr_narg = narg;
        argp = (int *)((char *)ktp + sizeof(struct ktr_syscall));
        for (i = 0; i < narg; i++)
        MALLOC(ktp, struct ktr_syscall *, len, M_TEMP, M_WAITOK);
        ktp->ktr_code = code;
        ktp->ktr_narg = narg;
        argp = (int *)((char *)ktp + sizeof(struct ktr_syscall));
        for (i = 0; i < narg; i++)
-               *argp++ = u.u_arg[i];
+               *argp++ = args[i];
        kth->ktr_buf = (caddr_t)ktp;
        kth->ktr_len = len;
        ktrwrite(vp, kth);
        kth->ktr_buf = (caddr_t)ktp;
        kth->ktr_len = len;
        ktrwrite(vp, kth);
@@ -71,26 +55,21 @@ ktrsyscall(vp, code, narg)
        FREE(kth, M_TEMP);
 }
 
        FREE(kth, M_TEMP);
 }
 
-ktrsysret(vp, code)
+ktrsysret(vp, code, error, retval)
        struct vnode *vp;
        struct vnode *vp;
+       int code, error, retval;
 {
        struct ktr_header *kth = ktrgetheader(KTR_SYSRET);
 {
        struct ktr_header *kth = ktrgetheader(KTR_SYSRET);
-       struct ktr_sysret *ktp;
+       struct ktr_sysret ktp;
 
 
-       if (kth == NULL)
-               return;
-       MALLOC(ktp, struct ktr_sysret *, sizeof(struct ktr_sysret),
-               M_TEMP , M_WAITOK);
-       ktp->ktr_code = code;
-       ktp->ktr_eosys = u.u_eosys;
-       ktp->ktr_error = u.u_error;
-       ktp->ktr_retval = u.u_r.r_val1;         /* what about val2 ? */
+       ktp.ktr_code = code;
+       ktp.ktr_error = error;
+       ktp.ktr_retval = retval;                /* what about val2 ? */
 
 
-       kth->ktr_buf = (caddr_t)ktp;
+       kth->ktr_buf = (caddr_t)&ktp;
        kth->ktr_len = sizeof(struct ktr_sysret);
 
        ktrwrite(vp, kth);
        kth->ktr_len = sizeof(struct ktr_sysret);
 
        ktrwrite(vp, kth);
-       FREE(ktp, M_TEMP);
        FREE(kth, M_TEMP);
 }
 
        FREE(kth, M_TEMP);
 }
 
@@ -100,8 +79,6 @@ ktrnamei(vp, path)
 {
        struct ktr_header *kth = ktrgetheader(KTR_NAMEI);
 
 {
        struct ktr_header *kth = ktrgetheader(KTR_NAMEI);
 
-       if (kth == NULL)
-               return;
        kth->ktr_len = strlen(path);
        kth->ktr_buf = path;
 
        kth->ktr_len = strlen(path);
        kth->ktr_buf = path;
 
@@ -109,8 +86,9 @@ ktrnamei(vp, path)
        FREE(kth, M_TEMP);
 }
 
        FREE(kth, M_TEMP);
 }
 
-ktrgenio(vp, fd, rw, iov, len)
+ktrgenio(vp, fd, rw, iov, len, error)
        struct vnode *vp;
        struct vnode *vp;
+       int fd;
        enum uio_rw rw;
        register struct iovec *iov;
 {
        enum uio_rw rw;
        register struct iovec *iov;
 {
@@ -119,7 +97,7 @@ ktrgenio(vp, fd, rw, iov, len)
        register caddr_t cp;
        register int resid = len, cnt;
        
        register caddr_t cp;
        register int resid = len, cnt;
        
-       if (kth == NULL || u.u_error)
+       if (error)
                return;
        MALLOC(ktp, struct ktr_genio *, sizeof(struct ktr_genio) + len,
                M_TEMP, M_WAITOK);
                return;
        MALLOC(ktp, struct ktr_genio *, sizeof(struct ktr_genio) + len,
                M_TEMP, M_WAITOK);
@@ -129,7 +107,7 @@ ktrgenio(vp, fd, rw, iov, len)
        while (resid > 0) {
                if ((cnt = iov->iov_len) > resid)
                        cnt = resid;
        while (resid > 0) {
                if ((cnt = iov->iov_len) > resid)
                        cnt = resid;
-               if (copyin(iov->iov_base, cp, cnt))
+               if (copyin(iov->iov_base, cp, (unsigned)cnt))
                        goto done;
                cp += cnt;
                resid -= cnt;
                        goto done;
                cp += cnt;
                resid -= cnt;
@@ -144,44 +122,63 @@ done:
        FREE(ktp, M_TEMP);
 }
 
        FREE(ktp, M_TEMP);
 }
 
+ktrpsig(vp, sig, action, mask, code)
+       struct  vnode *vp;
+       sig_t   action;
+{
+       struct ktr_header *kth = ktrgetheader(KTR_PSIG);
+       struct ktr_psig kp;
+
+       kp.signo = (char)sig;
+       kp.action = action;
+       kp.mask = mask;
+       kp.code = code;
+       kth->ktr_buf = (caddr_t)&kp;
+       kth->ktr_len = sizeof (struct ktr_psig);
+
+       ktrwrite(vp, kth);
+       FREE(kth, M_TEMP);
+}
+
+/* Interface and common routines */
+
 /*
  * ktrace system call
  */
 /*
  * ktrace system call
  */
-ktrace()
-{
-       register struct a {
+/* ARGSUSED */
+ktrace(curp, uap, retval)
+       struct proc *curp;
+       register struct args {
                char    *fname;
                int     ops;
                int     facs;
                int     pid;
                char    *fname;
                int     ops;
                int     facs;
                int     pid;
-       } *uap = (struct a *)u.u_ap;
+       } *uap;
+       int *retval;
+{
        register struct vnode *vp = NULL;
        register struct vnode *vp = NULL;
-       register struct nameidata *ndp = &u.u_nd;
        register struct proc *p;
        struct pgrp *pg;
        register struct proc *p;
        struct pgrp *pg;
-       register int ops = uap->ops&0x3;
-       register int facs = uap->facs;
-       register int ret = 0;
+       int facs = uap->facs & ~KTRFAC_ROOT;
+       int ops = KTROP(uap->ops);
+       int descend = uap->ops & KTRFLAG_DESCEND;
+       int ret = 0;
+       int error = 0;
+       struct nameidata nd;
 
 
-       /*
-        * Until security implications are thought through,
-        * limit tracing to root (unless ktrace_nocheck is set).
-        */
-       if (!ktrace_nocheck && (u.u_error = suser(u.u_cred, &u.u_acflag)))
-               return;
        if (ops != KTROP_CLEAR) {
                /*
                 * an operation which requires a file argument.
                 */
        if (ops != KTROP_CLEAR) {
                /*
                 * an operation which requires a file argument.
                 */
-               ndp->ni_segflg = UIO_USERSPACE;
-               ndp->ni_dirp = uap->fname;
-               if (u.u_error = vn_open(ndp, FREAD|FWRITE, 0))
-                       return;
-               vp = ndp->ni_vp;
+               nd.ni_segflg = UIO_USERSPACE;
+               nd.ni_dirp = uap->fname;
+               if (error = vn_open(&nd, curp, FREAD|FWRITE, 0))
+                       return (error);
+               vp = nd.ni_vp;
+               VOP_UNLOCK(vp);
                if (vp->v_type != VREG) {
                if (vp->v_type != VREG) {
-                       u.u_error = EACCES;
-                       vrele(vp);
-                       return;
+                       (void) vn_close(vp, FREAD|FWRITE, curp->p_ucred, curp);
+                       return (EACCES);
                }
        }
        /*
                }
        }
        /*
@@ -190,98 +187,109 @@ ktrace()
        if (ops == KTROP_CLEARFILE) {
                for (p = allproc; p != NULL; p = p->p_nxt) {
                        if (p->p_tracep == vp) {
        if (ops == KTROP_CLEARFILE) {
                for (p = allproc; p != NULL; p = p->p_nxt) {
                        if (p->p_tracep == vp) {
-                               p->p_flag &= ~SKTR;
-                               p->p_tracep = NULL;
-                               p->p_traceflag = 0;
-                               vrele(vp);
+                               if (ktrcanset(curp, p)) {
+                                       p->p_tracep = NULL;
+                                       p->p_traceflag = 0;
+                                       (void) vn_close(vp, FREAD|FWRITE,
+                                               p->p_ucred, p);
+                               } else
+                                       error = EPERM;
                        }
                }
                goto done;
        }
                        }
                }
                goto done;
        }
-
        /*
        /*
-        * need something to (un)trace
+        * need something to (un)trace (XXX - why is this here?)
         */
        if (!facs) {
         */
        if (!facs) {
-               u.u_error = EINVAL;
+               error = EINVAL;
                goto done;
        }
                goto done;
        }
-
+       /* 
+        * do it
+        */
        if (uap->pid < 0) {
        if (uap->pid < 0) {
+               /*
+                * by process group
+                */
                pg = pgfind(-uap->pid);
                if (pg == NULL) {
                pg = pgfind(-uap->pid);
                if (pg == NULL) {
-                       u.u_error = ESRCH;
+                       error = ESRCH;
                        goto done;
                }
                for (p = pg->pg_mem; p != NULL; p = p->p_pgrpnxt)
                        goto done;
                }
                for (p = pg->pg_mem; p != NULL; p = p->p_pgrpnxt)
-                       if (uap->ops&KTROP_INHERITFLAG)
-                               ret |= ktrsetchildren(p, ops, facs, vp);
+                       if (descend)
+                               ret |= ktrsetchildren(curp, p, ops, facs, vp);
                        else 
                        else 
-                               ret |= ktrops(p, ops, facs, vp);
+                               ret |= ktrops(curp, p, ops, facs, vp);
                                        
        } else {
                                        
        } else {
+               /*
+                * by pid
+                */
                p = pfind(uap->pid);
                if (p == NULL) {
                p = pfind(uap->pid);
                if (p == NULL) {
-                       u.u_error = ESRCH;
+                       error = ESRCH;
                        goto done;
                }
                        goto done;
                }
-               if (uap->ops&KTROP_INHERITFLAG)
-                       ret |= ktrsetchildren(p, ops, facs, vp);
+               if (descend)
+                       ret |= ktrsetchildren(curp, p, ops, facs, vp);
                else
                else
-                       ret |= ktrops(p, ops, facs, vp);
+                       ret |= ktrops(curp, p, ops, facs, vp);
        }
        if (!ret)
        }
        if (!ret)
-               u.u_error = EPERM;
+               error = EPERM;
 done:
        if (vp != NULL)
 done:
        if (vp != NULL)
-               vrele(vp);
+               (void) vn_close(vp, FWRITE, curp->p_ucred, curp);
+       return (error);
 }
 
 }
 
-ktrops(p, ops, facs, vp)
-       struct proc *p;
+ktrops(curp, p, ops, facs, vp)
+       struct proc *curp, *p;
        struct vnode *vp;
 {
 
        struct vnode *vp;
 {
 
-       if (u.u_uid && u.u_uid != p->p_uid)
-               return 0;
+       if (!ktrcanset(curp, p))
+               return (0);
        if (ops == KTROP_SET) {
        if (ops == KTROP_SET) {
-               if (p->p_tracep != vp) {
+               if (p->p_tracep != vp) { 
                        /*
                         * if trace file already in use, relinquish
                         */
                        if (p->p_tracep != NULL)
                                vrele(p->p_tracep);
                        /*
                         * if trace file already in use, relinquish
                         */
                        if (p->p_tracep != NULL)
                                vrele(p->p_tracep);
-                       if (vp->v_count == 0)
-                               panic("ktrace: bad vnode");
+                       VREF(vp);
                        p->p_tracep = vp;
                }
                p->p_traceflag |= facs;
                        p->p_tracep = vp;
                }
                p->p_traceflag |= facs;
+               if (curp->p_ucred->cr_uid == 0)
+                       p->p_traceflag |= KTRFAC_ROOT;
        } else {        
                /* KTROP_CLEAR */
        } else {        
                /* KTROP_CLEAR */
-               if ((p->p_traceflag &= ~facs) == 0) {
+               if (((p->p_traceflag &= ~facs) & KTRFAC_MASK) == 0) {
+                       /* no more tracing */
+                       p->p_traceflag = 0;
                        if (p->p_tracep != NULL) {
                                vrele(p->p_tracep);
                                p->p_tracep = NULL;
                        }
                        if (p->p_tracep != NULL) {
                                vrele(p->p_tracep);
                                p->p_tracep = NULL;
                        }
-                       p->p_flag &= ~SKTR;
                }
        }
 
                }
        }
 
-       return 1;
+       return (1);
 }
 
 }
 
-ktrsetchildren(top, ops, facs, vp)
-       struct proc *top;
+ktrsetchildren(curp, top, ops, facs, vp)
+       struct proc *curp, *top;
        struct vnode *vp;
 {
        register struct proc *p;
        struct vnode *vp;
 {
        register struct proc *p;
-       register int ndx;
        register int ret = 0;
 
        p = top;
        for (;;) {
        register int ret = 0;
 
        p = top;
        for (;;) {
-               if ((ret |= ktrops(p, ops, facs, vp)) && ops == KTROP_SET)
-                       p->p_flag |= SKTR;
+               ret |= ktrops(curp, p, ops, facs, vp);
                /*
                 * If this process has children, descend to them next,
                 * otherwise do any siblings, and if done with this level,
                /*
                 * If this process has children, descend to them next,
                 * otherwise do any siblings, and if done with this level,
@@ -290,13 +298,13 @@ ktrsetchildren(top, ops, facs, vp)
                if (p->p_cptr)
                        p = p->p_cptr;
                else if (p == top)
                if (p->p_cptr)
                        p = p->p_cptr;
                else if (p == top)
-                       return ret;
+                       return (ret);
                else if (p->p_osptr)
                        p = p->p_osptr;
                else for (;;) {
                        p = p->p_pptr;
                        if (p == top)
                else if (p->p_osptr)
                        p = p->p_osptr;
                else for (;;) {
                        p = p->p_pptr;
                        if (p == top)
-                               return ret;
+                               return (ret);
                        if (p->p_osptr) {
                                p = p->p_osptr;
                                break;
                        if (p->p_osptr) {
                                p = p->p_osptr;
                                break;
@@ -312,7 +320,8 @@ ktrwrite(vp, kth)
 {
        struct uio auio;
        struct iovec aiov[2];
 {
        struct uio auio;
        struct iovec aiov[2];
-       int offset, error;
+       register struct proc *p = curproc;      /* XXX */
+       int error;
 
        if (vp == NULL)
                return;
 
        if (vp == NULL)
                return;
@@ -324,12 +333,56 @@ ktrwrite(vp, kth)
        aiov[0].iov_len = sizeof(struct ktr_header);
        auio.uio_resid = sizeof(struct ktr_header);
        auio.uio_iovcnt = 1;
        aiov[0].iov_len = sizeof(struct ktr_header);
        auio.uio_resid = sizeof(struct ktr_header);
        auio.uio_iovcnt = 1;
+       auio.uio_procp = (struct proc *)0;
        if (kth->ktr_len > 0) {
                auio.uio_iovcnt++;
                aiov[1].iov_base = kth->ktr_buf;
                aiov[1].iov_len = kth->ktr_len;
                auio.uio_resid += kth->ktr_len;
        }
        if (kth->ktr_len > 0) {
                auio.uio_iovcnt++;
                aiov[1].iov_base = kth->ktr_buf;
                aiov[1].iov_len = kth->ktr_len;
                auio.uio_resid += kth->ktr_len;
        }
-       error = VOP_WRITE(vp, &auio, &offset, IO_UNIT|IO_APPEND, u.u_cred);
+       VOP_LOCK(vp);
+       error = VOP_WRITE(vp, &auio, IO_UNIT|IO_APPEND, p->p_ucred);
+       VOP_UNLOCK(vp);
+       if (!error)
+               return;
+       /*
+        * If error encountered, give up tracing on this vnode.
+        */
+       log(LOG_NOTICE, "ktrace write failed, errno %d, tracing stopped\n",
+           error);
+       for (p = allproc; p != NULL; p = p->p_nxt) {
+               if (p->p_tracep == vp) {
+                       p->p_tracep = NULL;
+                       p->p_traceflag = 0;
+                       vrele(vp);
+               }
+       }
 }
 }
+
+/*
+ * Return true if caller has permission to set the ktracing state
+ * of target.  Essentially, the target can't possess any
+ * more permissions than the caller.  KTRFAC_ROOT signifies that
+ * root previously set the tracing status on the target process, and 
+ * so, only root may further change it.
+ *
+ * TODO: check groups.  use caller effective gid.
+ */
+ktrcanset(callp, targetp)
+       struct proc *callp, *targetp;
+{
+       register struct pcred *caller = callp->p_cred;
+       register struct pcred *target = targetp->p_cred;
+
+       if ((caller->pc_ucred->cr_uid == target->p_ruid &&
+            target->p_ruid == target->p_svuid &&
+            caller->p_rgid == target->p_rgid &&        /* XXX */
+            target->p_rgid == target->p_svgid &&
+            (targetp->p_traceflag & KTRFAC_ROOT) == 0) ||
+            caller->pc_ucred->cr_uid == 0)
+               return (1);
+
+       return (0);
+}
+
 #endif
 #endif