ec_rxstart doesn't eists
[unix-history] / usr / src / sys / kern / kern_ktrace.c
index 67f818d..884cb4a 100644 (file)
@@ -2,49 +2,34 @@
  * 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       7.6 (Berkeley) %G%
+ *     @(#)kern_ktrace.c       7.15 (Berkeley) %G%
  */
 
 #ifdef KTRACE
 
 #include "param.h"
  */
 
 #ifdef KTRACE
 
 #include "param.h"
-#include "syscontext.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_procp->p_comm, kth->ktr_comm, MAXCOMLEN);
+       kth->ktr_pid = p->p_pid;
+       bcopy(p->p_comm, kth->ktr_comm, MAXCOMLEN);
        return (kth);
 }
 
        return (kth);
 }
 
@@ -57,8 +42,6 @@ ktrsyscall(vp, code, narg, args)
        register len = sizeof(struct ktr_syscall) + (narg * sizeof(int));
        int     *argp, i;
 
        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;
        MALLOC(ktp, struct ktr_syscall *, len, M_TEMP, M_WAITOK);
        ktp->ktr_code = code;
        ktp->ktr_narg = narg;
@@ -79,8 +62,6 @@ ktrsysret(vp, code, error, retval)
        struct ktr_header *kth = ktrgetheader(KTR_SYSRET);
        struct ktr_sysret ktp;
 
        struct ktr_header *kth = ktrgetheader(KTR_SYSRET);
        struct ktr_sysret ktp;
 
-       if (kth == NULL)
-               return;
        ktp.ktr_code = code;
        ktp.ktr_error = error;
        ktp.ktr_retval = retval;                /* what about val2 ? */
        ktp.ktr_code = code;
        ktp.ktr_error = error;
        ktp.ktr_retval = retval;                /* what about val2 ? */
@@ -98,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;
 
@@ -118,7 +97,7 @@ ktrgenio(vp, fd, rw, iov, len, error)
        register caddr_t cp;
        register int resid = len, cnt;
        
        register caddr_t cp;
        register int resid = len, cnt;
        
-       if (kth == NULL || 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);
@@ -150,8 +129,6 @@ ktrpsig(vp, sig, action, mask, code)
        struct ktr_header *kth = ktrgetheader(KTR_PSIG);
        struct ktr_psig kp;
 
        struct ktr_header *kth = ktrgetheader(KTR_PSIG);
        struct ktr_psig kp;
 
-       if (kth == NULL)
-               return;
        kp.signo = (char)sig;
        kp.action = action;
        kp.mask = mask;
        kp.signo = (char)sig;
        kp.action = action;
        kp.mask = mask;
@@ -180,32 +157,28 @@ ktrace(curp, uap, retval)
        int *retval;
 {
        register struct vnode *vp = NULL;
        int *retval;
 {
        register struct vnode *vp = NULL;
-       register struct nameidata *ndp = &u.u_nd;
        register struct proc *p;
        register struct proc *p;
-       register ops = KTROP(uap->ops);
        struct pgrp *pg;
        struct pgrp *pg;
-       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;
        int error = 0;
+       struct nameidata nd;
 
 
-       /*
-        * Until security implications are thought through,
-        * limit tracing to root (unless ktrace_nocheck is set).
-        */
-       if (!ktrace_nocheck && (error = suser(u.u_cred, &u.u_acflag)))
-               RETURN (error);
        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 (error = vn_open(ndp, FREAD|FWRITE, 0))
-                       RETURN (error);
-               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) {
-                       vrele(vp);
-                       RETURN (EACCES);
+                       (void) vn_close(vp, FREAD|FWRITE, curp->p_ucred, curp);
+                       return (EACCES);
                }
        }
        /*
                }
        }
        /*
@@ -214,61 +187,71 @@ ktrace(curp, uap, retval)
        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_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) {
                error = EINVAL;
                goto done;
        }
        /* 
         */
        if (!facs) {
                error = EINVAL;
                goto done;
        }
        /* 
-        * doit
+        * do it
         */
        if (uap->pid < 0) {
         */
        if (uap->pid < 0) {
+               /*
+                * by process group
+                */
                pg = pgfind(-uap->pid);
                if (pg == NULL) {
                        error = ESRCH;
                        goto done;
                }
                for (p = pg->pg_mem; p != NULL; p = p->p_pgrpnxt)
                pg = pgfind(-uap->pid);
                if (pg == NULL) {
                        error = ESRCH;
                        goto done;
                }
                for (p = pg->pg_mem; p != NULL; p = p->p_pgrpnxt)
-                       if (uap->ops&KTRFLAG_DESCEND)
-                               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) {
                        error = ESRCH;
                        goto done;
                }
                p = pfind(uap->pid);
                if (p == NULL) {
                        error = ESRCH;
                        goto done;
                }
-               if (ops&KTRFLAG_DESCEND)
-                       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)
                error = EPERM;
 done:
        if (vp != NULL)
        }
        if (!ret)
                error = EPERM;
 done:
        if (vp != NULL)
-               vrele(vp);
-       RETURN (error);
+               (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 (p->p_tracep != vp) { 
                        /*
        if (ops == KTROP_SET) {
                if (p->p_tracep != vp) { 
                        /*
@@ -280,9 +263,11 @@ ktrops(p, ops, facs, 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) & ~KTRFAC_INHERIT) == 0) {
+               if (((p->p_traceflag &= ~facs) & KTRFAC_MASK) == 0) {
                        /* no more tracing */
                        p->p_traceflag = 0;
                        if (p->p_tracep != NULL) {
                        /* no more tracing */
                        p->p_traceflag = 0;
                        if (p->p_tracep != NULL) {
@@ -292,11 +277,11 @@ ktrops(p, ops, facs, vp)
                }
        }
 
                }
        }
 
-       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;
@@ -304,7 +289,7 @@ ktrsetchildren(top, ops, facs, vp)
 
        p = top;
        for (;;) {
 
        p = top;
        for (;;) {
-               ret |= ktrops(p, ops, facs, vp);
+               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,
@@ -313,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;
@@ -335,7 +320,7 @@ ktrwrite(vp, kth)
 {
        struct uio auio;
        struct iovec aiov[2];
 {
        struct uio auio;
        struct iovec aiov[2];
-       struct proc *p;
+       register struct proc *p = curproc;      /* XXX */
        int error;
 
        if (vp == NULL)
        int error;
 
        if (vp == NULL)
@@ -348,6 +333,7 @@ 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;
        if (kth->ktr_len > 0) {
                auio.uio_iovcnt++;
                aiov[1].iov_base = kth->ktr_buf;
@@ -355,14 +341,15 @@ ktrwrite(vp, kth)
                auio.uio_resid += kth->ktr_len;
        }
        VOP_LOCK(vp);
                auio.uio_resid += kth->ktr_len;
        }
        VOP_LOCK(vp);
-       error = VOP_WRITE(vp, &auio, IO_UNIT|IO_APPEND, u.u_cred);
+       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.
         */
        VOP_UNLOCK(vp);
        if (!error)
                return;
        /*
         * If error encountered, give up tracing on this vnode.
         */
-       uprintf("\ntrace write failed with errno %d, tracing stopped\n", error);
+       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;
        for (p = allproc; p != NULL; p = p->p_nxt) {
                if (p->p_tracep == vp) {
                        p->p_tracep = NULL;
@@ -371,4 +358,31 @@ ktrwrite(vp, kth)
                }
        }
 }
                }
        }
 }
+
+/*
+ * 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