Annotation of src/sys/kern/kern_ktrace.c, Revision 1.54
1.54 ! thorpej 1: /* $NetBSD: kern_ktrace.c,v 1.53 2001/01/05 22:25:26 jdolecek Exp $ */
1.11 cgd 2:
1.1 cgd 3: /*
1.9 cgd 4: * Copyright (c) 1989, 1993
5: * The Regents of the University of California. All rights reserved.
1.1 cgd 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: *
1.25 fvdl 35: * @(#)kern_ktrace.c 8.5 (Berkeley) 5/14/95
1.1 cgd 36: */
1.29 thorpej 37:
38: #include "opt_ktrace.h"
1.1 cgd 39:
1.7 mycroft 40: #include <sys/param.h>
1.13 cgd 41: #include <sys/systm.h>
1.7 mycroft 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>
1.28 christos 49: #include <sys/filedesc.h>
1.42 sommerfe 50: #include <sys/ioctl.h>
1.1 cgd 51:
1.13 cgd 52: #include <sys/mount.h>
53: #include <sys/syscallargs.h>
1.22 christos 54:
1.51 jdolecek 55: #ifdef KTRACE
56:
1.47 thorpej 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 *);
1.44 sommerfe 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
1.47 thorpej 73: ktrsamefile(struct file *f1, struct file *f2)
1.44 sommerfe 74: {
75: return ((f1 == f2) ||
1.45 sommerfe 76: ((f1 != NULL) && (f2 != NULL) &&
77: (f1->f_type == f2->f_type) &&
1.44 sommerfe 78: (f1->f_data == f2->f_data)));
79: }
1.22 christos 80:
1.28 christos 81: void
1.47 thorpej 82: ktrderef(struct proc *p)
1.28 christos 83: {
1.42 sommerfe 84: struct file *fp = p->p_tracep;
85: p->p_traceflag = 0;
86: if (fp == NULL)
1.28 christos 87: return;
1.42 sommerfe 88: FILE_USE(fp);
89: closef(fp, NULL);
1.28 christos 90:
91: p->p_tracep = NULL;
92: }
93:
94: void
1.47 thorpej 95: ktradref(struct proc *p)
1.28 christos 96: {
1.42 sommerfe 97: struct file *fp = p->p_tracep;
1.28 christos 98:
1.42 sommerfe 99: fp->f_count++;
1.28 christos 100: }
101:
1.39 thorpej 102: void
1.47 thorpej 103: ktrinitheader(struct ktr_header *kth, struct proc *p, int type)
1.1 cgd 104: {
105:
1.39 thorpej 106: memset(kth, 0, sizeof(*kth));
1.1 cgd 107: kth->ktr_type = type;
108: microtime(&kth->ktr_time);
109: kth->ktr_pid = p->p_pid;
1.32 perry 110: memcpy(kth->ktr_comm, p->p_comm, MAXCOMLEN);
1.1 cgd 111: }
112:
1.17 cgd 113: void
1.47 thorpej 114: ktrsyscall(struct proc *p, register_t code, size_t argsize, register_t args[])
1.1 cgd 115: {
1.39 thorpej 116: struct ktr_header kth;
117: struct ktr_syscall *ktp;
1.17 cgd 118: register_t *argp;
1.39 thorpej 119: size_t len = sizeof(struct ktr_syscall) + argsize;
1.17 cgd 120: int i;
1.1 cgd 121:
1.9 cgd 122: p->p_traceflag |= KTRFAC_ACTIVE;
1.39 thorpej 123: ktrinitheader(&kth, p, KTR_SYSCALL);
124: ktp = malloc(len, M_TEMP, M_WAITOK);
1.1 cgd 125: ktp->ktr_code = code;
1.17 cgd 126: ktp->ktr_argsize = argsize;
127: argp = (register_t *)((char *)ktp + sizeof(struct ktr_syscall));
1.31 perry 128: for (i = 0; i < (argsize / sizeof(*argp)); i++)
1.1 cgd 129: *argp++ = args[i];
1.39 thorpej 130: kth.ktr_buf = (caddr_t)ktp;
131: kth.ktr_len = len;
1.42 sommerfe 132: (void) ktrwrite(p, &kth);
1.39 thorpej 133: free(ktp, M_TEMP);
1.9 cgd 134: p->p_traceflag &= ~KTRFAC_ACTIVE;
1.1 cgd 135: }
136:
1.17 cgd 137: void
1.47 thorpej 138: ktrsysret(struct proc *p, register_t code, int error, register_t retval)
1.1 cgd 139: {
1.39 thorpej 140: struct ktr_header kth;
1.1 cgd 141: struct ktr_sysret ktp;
142:
1.9 cgd 143: p->p_traceflag |= KTRFAC_ACTIVE;
1.39 thorpej 144: ktrinitheader(&kth, p, KTR_SYSRET);
1.1 cgd 145: ktp.ktr_code = code;
1.34 kleink 146: ktp.ktr_eosys = 0; /* XXX unused */
1.1 cgd 147: ktp.ktr_error = error;
148: ktp.ktr_retval = retval; /* what about val2 ? */
149:
1.39 thorpej 150: kth.ktr_buf = (caddr_t)&ktp;
151: kth.ktr_len = sizeof(struct ktr_sysret);
1.1 cgd 152:
1.42 sommerfe 153: (void) ktrwrite(p, &kth);
1.9 cgd 154: p->p_traceflag &= ~KTRFAC_ACTIVE;
1.1 cgd 155: }
156:
1.17 cgd 157: void
1.47 thorpej 158: ktrnamei(struct proc *p, char *path)
1.1 cgd 159: {
1.39 thorpej 160: struct ktr_header kth;
1.1 cgd 161:
1.9 cgd 162: p->p_traceflag |= KTRFAC_ACTIVE;
1.39 thorpej 163: ktrinitheader(&kth, p, KTR_NAMEI);
164: kth.ktr_len = strlen(path);
165: kth.ktr_buf = path;
1.18 christos 166:
1.42 sommerfe 167: (void) ktrwrite(p, &kth);
1.18 christos 168: p->p_traceflag &= ~KTRFAC_ACTIVE;
169: }
170:
171: void
1.47 thorpej 172: ktremul(struct proc *p)
1.18 christos 173: {
1.39 thorpej 174: struct ktr_header kth;
1.50 scw 175: const char *emul = p->p_emul->e_name;
1.18 christos 176:
177: p->p_traceflag |= KTRFAC_ACTIVE;
1.39 thorpej 178: ktrinitheader(&kth, p, KTR_EMUL);
179: kth.ktr_len = strlen(emul);
1.50 scw 180: kth.ktr_buf = (caddr_t)emul;
1.1 cgd 181:
1.42 sommerfe 182: (void) ktrwrite(p, &kth);
1.9 cgd 183: p->p_traceflag &= ~KTRFAC_ACTIVE;
1.1 cgd 184: }
185:
1.17 cgd 186: void
1.47 thorpej 187: ktrgenio(struct proc *p, int fd, enum uio_rw rw, struct iovec *iov,
188: int len, int error)
1.1 cgd 189: {
1.39 thorpej 190: struct ktr_header kth;
1.28 christos 191: struct ktr_genio *ktp;
192: caddr_t cp;
193: int resid = len, cnt;
1.39 thorpej 194: int buflen;
195:
1.1 cgd 196: if (error)
197: return;
1.39 thorpej 198:
1.9 cgd 199: p->p_traceflag |= KTRFAC_ACTIVE;
1.39 thorpej 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);
1.1 cgd 205: ktp->ktr_fd = fd;
206: ktp->ktr_rw = rw;
1.39 thorpej 207:
208: kth.ktr_buf = (caddr_t)ktp;
209:
1.31 perry 210: cp = (caddr_t)((char *)ktp + sizeof(struct ktr_genio));
1.39 thorpej 211: buflen -= sizeof(struct ktr_genio);
212:
1.1 cgd 213: while (resid > 0) {
1.46 thorpej 214: KDASSERT(p->p_cpu != NULL);
215: KDASSERT(p->p_cpu == curcpu());
216: if (p->p_cpu->ci_schedstate.spc_flags & SPCF_SHOULDYIELD)
1.39 thorpej 217: preempt(NULL);
218:
219: cnt = min(iov->iov_len, buflen);
220: if (cnt > resid)
1.1 cgd 221: cnt = resid;
1.39 thorpej 222: if (copyin(iov->iov_base, cp, cnt))
223: break;
224:
225: kth.ktr_len = cnt + sizeof(struct ktr_genio);
226:
1.42 sommerfe 227: if (__predict_false(ktrwrite(p, &kth) != 0))
1.39 thorpej 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:
1.1 cgd 236: resid -= cnt;
237: }
238:
1.39 thorpej 239: free(ktp, M_TEMP);
1.9 cgd 240: p->p_traceflag &= ~KTRFAC_ACTIVE;
1.1 cgd 241: }
242:
1.17 cgd 243: void
1.47 thorpej 244: ktrpsig(struct proc *p, int sig, sig_t action, sigset_t *mask, int code)
1.1 cgd 245: {
1.39 thorpej 246: struct ktr_header kth;
1.1 cgd 247: struct ktr_psig kp;
248:
1.9 cgd 249: p->p_traceflag |= KTRFAC_ACTIVE;
1.39 thorpej 250: ktrinitheader(&kth, p, KTR_PSIG);
1.1 cgd 251: kp.signo = (char)sig;
252: kp.action = action;
1.33 mycroft 253: kp.mask = *mask;
1.1 cgd 254: kp.code = code;
1.39 thorpej 255: kth.ktr_buf = (caddr_t)&kp;
256: kth.ktr_len = sizeof(struct ktr_psig);
1.1 cgd 257:
1.42 sommerfe 258: (void) ktrwrite(p, &kth);
1.9 cgd 259: p->p_traceflag &= ~KTRFAC_ACTIVE;
260: }
261:
1.17 cgd 262: void
1.47 thorpej 263: ktrcsw(struct proc *p, int out, int user)
1.9 cgd 264: {
1.39 thorpej 265: struct ktr_header kth;
266: struct ktr_csw kc;
1.9 cgd 267:
268: p->p_traceflag |= KTRFAC_ACTIVE;
1.39 thorpej 269: ktrinitheader(&kth, p, KTR_CSW);
1.9 cgd 270: kc.out = out;
271: kc.user = user;
1.39 thorpej 272: kth.ktr_buf = (caddr_t)&kc;
273: kth.ktr_len = sizeof(struct ktr_csw);
1.9 cgd 274:
1.42 sommerfe 275: (void) ktrwrite(p, &kth);
1.9 cgd 276: p->p_traceflag &= ~KTRFAC_ACTIVE;
1.1 cgd 277: }
278:
1.51 jdolecek 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:
1.1 cgd 314: /* Interface and common routines */
315:
1.17 cgd 316: int
1.47 thorpej 317: ktrace_common(struct proc *curp, int ops, int facs, int pid, struct file *fp)
1.28 christos 318: {
1.42 sommerfe 319: int ret = 0;
320: int error = 0;
321: int one = 1;
322: int descend;
1.28 christos 323: struct proc *p;
324: struct pgrp *pg;
325:
326: curp->p_traceflag |= KTRFAC_ACTIVE;
1.42 sommerfe 327: descend = ops & KTRFLAG_DESCEND;
328: facs = facs & ~((unsigned) KTRFAC_ROOT);
1.28 christos 329:
330: /*
331: * Clear all uses of the tracefile
332: */
333: if (KTROP(ops) == KTROP_CLEARFILE) {
1.37 thorpej 334: proclist_lock_read();
1.39 thorpej 335: for (p = LIST_FIRST(&allproc); p != NULL;
336: p = LIST_NEXT(p, p_list)) {
1.44 sommerfe 337: if (ktrsamefile(p->p_tracep, fp)) {
1.28 christos 338: if (ktrcanset(curp, p))
339: ktrderef(p);
340: else
341: error = EPERM;
342: }
343: }
1.36 thorpej 344: proclist_unlock_read();
1.28 christos 345: goto done;
346: }
1.42 sommerfe 347:
348: /*
349: * Mark fp non-blocking, to avoid problems from possible deadlocks.
350: */
351:
1.43 sommerfe 352: if (fp != NULL) {
353: fp->f_flag |= FNONBLOCK;
354: (*fp->f_ops->fo_ioctl)(fp, FIONBIO, (caddr_t)&one, curp);
355: }
1.42 sommerfe 356:
1.28 christos 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: */
1.42 sommerfe 367: if (pid < 0) {
1.28 christos 368: /*
369: * by process group
370: */
1.42 sommerfe 371: pg = pgfind(-pid);
1.28 christos 372: if (pg == NULL) {
373: error = ESRCH;
374: goto done;
375: }
1.39 thorpej 376: for (p = LIST_FIRST(&pg->pg_members); p != NULL;
377: p = LIST_NEXT(p, p_pglist)) {
1.28 christos 378: if (descend)
379: ret |= ktrsetchildren(curp, p, ops, facs, fp);
380: else
381: ret |= ktrops(curp, p, ops, facs, fp);
1.39 thorpej 382: }
1.28 christos 383:
384: } else {
385: /*
386: * by pid
387: */
1.42 sommerfe 388: p = pfind(pid);
1.28 christos 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
1.47 thorpej 410: sys_fktrace(struct proc *curp, void *v, register_t *retval)
1.42 sommerfe 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:
1.54 ! thorpej 421: if ((fp = fd_getfile(fdp, SCARG(uap, fd))) == NULL)
! 422: return (EBADF);
! 423:
! 424: if ((fp->f_flag & FWRITE) == 0)
1.42 sommerfe 425: return (EBADF);
426:
427: return ktrace_common(curp, SCARG(uap, ops),
428: SCARG(uap, facs), SCARG(uap, pid), fp);
429: }
430:
431: /*
432: * ktrace system call
433: */
434: /* ARGSUSED */
435: int
1.47 thorpej 436: sys_ktrace(struct proc *curp, void *v, register_t *retval)
1.19 thorpej 437: {
1.28 christos 438: struct sys_ktrace_args /* {
1.24 mycroft 439: syscallarg(const char *) fname;
1.13 cgd 440: syscallarg(int) ops;
441: syscallarg(int) facs;
442: syscallarg(int) pid;
1.19 thorpej 443: } */ *uap = v;
1.28 christos 444: struct vnode *vp = NULL;
1.42 sommerfe 445: struct file *fp = NULL;
446: int fd;
447: int ops = SCARG(uap, ops);
1.1 cgd 448: int error = 0;
449: struct nameidata nd;
450:
1.42 sommerfe 451: ops = KTROP(ops) | (ops & KTRFLAG_DESCEND);
452:
1.9 cgd 453: curp->p_traceflag |= KTRFAC_ACTIVE;
1.1 cgd 454: if (ops != KTROP_CLEAR) {
455: /*
456: * an operation which requires a file argument.
457: */
1.13 cgd 458: NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, fname),
459: curp);
1.22 christos 460: if ((error = vn_open(&nd, FREAD|FWRITE, 0)) != 0) {
1.9 cgd 461: curp->p_traceflag &= ~KTRFAC_ACTIVE;
1.1 cgd 462: return (error);
1.9 cgd 463: }
1.1 cgd 464: vp = nd.ni_vp;
1.25 fvdl 465: VOP_UNLOCK(vp, 0);
1.1 cgd 466: if (vp->v_type != VREG) {
467: (void) vn_close(vp, FREAD|FWRITE, curp->p_ucred, curp);
1.9 cgd 468: curp->p_traceflag &= ~KTRFAC_ACTIVE;
1.1 cgd 469: return (EACCES);
470: }
471: /*
1.42 sommerfe 472: * XXX This uses up a file descriptor slot in the
473: * tracing process for the duration of this syscall.
474: * This is not expected to be a problem. If
475: * falloc(NULL, ...) DTRT we could skip that part, but
476: * that would require changing its interface to allow
477: * the caller to pass in a ucred..
478: *
479: * This will FILE_USE the fp it returns, if any.
480: * Keep it in use until we return.
1.1 cgd 481: */
1.42 sommerfe 482: if ((error = falloc(curp, &fp, &fd)) != 0)
1.1 cgd 483: goto done;
1.42 sommerfe 484:
485: fp->f_flag = FWRITE|FAPPEND;
486: fp->f_type = DTYPE_VNODE;
487: fp->f_ops = &vnops;
488: fp->f_data = (caddr_t)vp;
1.54 ! thorpej 489: FILE_SET_MATURE(fp);
1.42 sommerfe 490: vp = NULL;
491: }
492: error = ktrace_common(curp, SCARG(uap, ops), SCARG(uap, facs),
493: SCARG(uap, pid), fp);
494: done:
1.1 cgd 495: if (vp != NULL)
496: (void) vn_close(vp, FWRITE, curp->p_ucred, curp);
1.42 sommerfe 497: if (fp != NULL) {
1.44 sommerfe 498: FILE_UNUSE(fp, curp); /* release file */
1.42 sommerfe 499: fdrelease(curp, fd); /* release fd table slot */
500: }
1.1 cgd 501: return (error);
502: }
503:
1.4 andrew 504: int
1.47 thorpej 505: ktrops(struct proc *curp, struct proc *p, int ops, int facs, struct file *fp)
1.1 cgd 506: {
507:
508: if (!ktrcanset(curp, p))
509: return (0);
1.28 christos 510: if (KTROP(ops) == KTROP_SET) {
1.42 sommerfe 511: if (p->p_tracep != fp) {
1.1 cgd 512: /*
513: * if trace file already in use, relinquish
514: */
1.28 christos 515: ktrderef(p);
1.42 sommerfe 516: p->p_tracep = fp;
1.28 christos 517: ktradref(p);
1.1 cgd 518: }
519: p->p_traceflag |= facs;
520: if (curp->p_ucred->cr_uid == 0)
521: p->p_traceflag |= KTRFAC_ROOT;
522: } else {
523: /* KTROP_CLEAR */
524: if (((p->p_traceflag &= ~facs) & KTRFAC_MASK) == 0) {
525: /* no more tracing */
1.28 christos 526: ktrderef(p);
1.1 cgd 527: }
528: }
1.21 christos 529:
530: /*
531: * Emit an emulation record, every time there is a ktrace
532: * change/attach request.
533: */
534: if (KTRPOINT(p, KTR_EMUL))
1.42 sommerfe 535: ktremul(p);
1.49 martin 536: #ifdef __HAVE_SYSCALL_INTERN
1.48 mycroft 537: (*p->p_emul->e_syscall_intern)(p);
1.49 martin 538: #endif
1.1 cgd 539:
540: return (1);
541: }
542:
1.22 christos 543: int
1.47 thorpej 544: ktrsetchildren(struct proc *curp, struct proc *top, int ops, int facs,
545: struct file *fp)
1.1 cgd 546: {
1.28 christos 547: struct proc *p;
548: int ret = 0;
1.1 cgd 549:
550: p = top;
551: for (;;) {
1.42 sommerfe 552: ret |= ktrops(curp, p, ops, facs, fp);
1.1 cgd 553: /*
554: * If this process has children, descend to them next,
555: * otherwise do any siblings, and if done with this level,
556: * follow back up the tree (but not past top).
557: */
1.39 thorpej 558: if (LIST_FIRST(&p->p_children) != NULL)
559: p = LIST_FIRST(&p->p_children);
1.1 cgd 560: else for (;;) {
561: if (p == top)
562: return (ret);
1.39 thorpej 563: if (LIST_NEXT(p, p_sibling) != NULL) {
564: p = LIST_NEXT(p, p_sibling);
1.1 cgd 565: break;
566: }
1.12 mycroft 567: p = p->p_pptr;
1.1 cgd 568: }
569: }
570: /*NOTREACHED*/
571: }
572:
1.39 thorpej 573: int
1.47 thorpej 574: ktrwrite(struct proc *p, struct ktr_header *kth)
1.1 cgd 575: {
576: struct uio auio;
577: struct iovec aiov[2];
1.42 sommerfe 578: int error, tries;
579: struct file *fp = p->p_tracep;
1.1 cgd 580:
1.42 sommerfe 581: if (fp == NULL)
582: return 0;
583:
1.1 cgd 584: auio.uio_iov = &aiov[0];
585: auio.uio_offset = 0;
586: auio.uio_segflg = UIO_SYSSPACE;
587: auio.uio_rw = UIO_WRITE;
588: aiov[0].iov_base = (caddr_t)kth;
589: aiov[0].iov_len = sizeof(struct ktr_header);
590: auio.uio_resid = sizeof(struct ktr_header);
591: auio.uio_iovcnt = 1;
592: auio.uio_procp = (struct proc *)0;
593: if (kth->ktr_len > 0) {
594: auio.uio_iovcnt++;
595: aiov[1].iov_base = kth->ktr_buf;
596: aiov[1].iov_len = kth->ktr_len;
597: auio.uio_resid += kth->ktr_len;
598: }
1.28 christos 599:
1.42 sommerfe 600: FILE_USE(fp);
601:
602: tries = 0;
603: do {
1.30 thorpej 604: error = (*fp->f_ops->fo_write)(fp, &fp->f_offset, &auio,
605: fp->f_cred, FOF_UPDATE_OFFSET);
1.42 sommerfe 606: tries++;
607: if (error == EWOULDBLOCK)
608: yield();
609: } while ((error == EWOULDBLOCK) && (tries < 3));
610: FILE_UNUSE(fp, NULL);
1.28 christos 611:
1.40 thorpej 612: if (__predict_true(error == 0))
1.39 thorpej 613: return (0);
1.1 cgd 614: /*
1.38 darrenr 615: * If error encountered, give up tracing on this vnode. Don't report
616: * EPIPE as this can easily happen with fktrace()/ktruss.
1.1 cgd 617: */
1.38 darrenr 618: if (error != EPIPE)
619: log(LOG_NOTICE,
620: "ktrace write failed, errno %d, tracing stopped\n",
621: error);
1.37 thorpej 622: proclist_lock_read();
1.39 thorpej 623: for (p = LIST_FIRST(&allproc); p != NULL; p = LIST_NEXT(p, p_list)) {
1.44 sommerfe 624: if (ktrsamefile(p->p_tracep, fp))
1.28 christos 625: ktrderef(p);
1.1 cgd 626: }
1.36 thorpej 627: proclist_unlock_read();
1.39 thorpej 628:
629: return (error);
1.1 cgd 630: }
631:
632: /*
633: * Return true if caller has permission to set the ktracing state
634: * of target. Essentially, the target can't possess any
635: * more permissions than the caller. KTRFAC_ROOT signifies that
636: * root previously set the tracing status on the target process, and
637: * so, only root may further change it.
638: *
639: * TODO: check groups. use caller effective gid.
640: */
1.22 christos 641: int
1.47 thorpej 642: ktrcanset(struct proc *callp, struct proc *targetp)
1.1 cgd 643: {
1.28 christos 644: struct pcred *caller = callp->p_cred;
645: struct pcred *target = targetp->p_cred;
1.1 cgd 646:
647: if ((caller->pc_ucred->cr_uid == target->p_ruid &&
648: target->p_ruid == target->p_svuid &&
649: caller->p_rgid == target->p_rgid && /* XXX */
650: target->p_rgid == target->p_svgid &&
651: (targetp->p_traceflag & KTRFAC_ROOT) == 0) ||
652: caller->pc_ucred->cr_uid == 0)
653: return (1);
654:
655: return (0);
656: }
1.47 thorpej 657: #endif /* KTRACE */
1.51 jdolecek 658:
659: /*
660: * Put user defined entry to ktrace records.
661: */
662: int
663: sys_utrace(p, v, retval)
664: struct proc *p;
665: void *v;
666: register_t *retval;
667: {
668: #ifdef KTRACE
669: struct sys_utrace_args /* {
1.52 jdolecek 670: syscallarg(const char *) label;
1.51 jdolecek 671: syscallarg(void *) addr;
672: syscallarg(size_t) len;
673: } */ *uap = v;
674:
675: if (!KTRPOINT(p, KTR_USER))
676: return (0);
1.53 jdolecek 677:
678: if (SCARG(uap, len) > KTR_USER_MAXLEN)
679: return (EINVAL);
1.51 jdolecek 680:
1.52 jdolecek 681: ktruser(p, SCARG(uap, label), SCARG(uap, addr), SCARG(uap, len), 1);
1.51 jdolecek 682:
683: return (0);
684: #else /* !KTRACE */
685: return ENOSYS;
686: #endif /* KTRACE */
687: }
CVSweb <webmaster@jp.NetBSD.org>