Annotation of src/sys/kern/kern_ktrace.c, Revision 1.63
1.63 ! christos 1: /* $NetBSD: kern_ktrace.c,v 1.62 2002/12/09 21:29:21 manu 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.55 lukem 37:
38: #include <sys/cdefs.h>
1.63 ! christos 39: __KERNEL_RCSID(0, "$NetBSD: kern_ktrace.c,v 1.62 2002/12/09 21:29:21 manu Exp $");
1.29 thorpej 40:
41: #include "opt_ktrace.h"
1.62 manu 42: #include "opt_compat_mach.h"
1.1 cgd 43:
1.7 mycroft 44: #include <sys/param.h>
1.13 cgd 45: #include <sys/systm.h>
1.7 mycroft 46: #include <sys/proc.h>
47: #include <sys/file.h>
48: #include <sys/namei.h>
49: #include <sys/vnode.h>
50: #include <sys/ktrace.h>
51: #include <sys/malloc.h>
52: #include <sys/syslog.h>
1.28 christos 53: #include <sys/filedesc.h>
1.42 sommerfe 54: #include <sys/ioctl.h>
1.1 cgd 55:
1.13 cgd 56: #include <sys/mount.h>
57: #include <sys/syscallargs.h>
1.22 christos 58:
1.62 manu 59: #ifdef COMPAT_MACH
60: #include <compat/mach/mach_types.h>
61: #include <compat/mach/mach_message.h>
62: #endif
63:
1.51 jdolecek 64: #ifdef KTRACE
65:
1.47 thorpej 66: int ktrace_common(struct proc *, int, int, int, struct file *);
67: void ktrinitheader(struct ktr_header *, struct proc *, int);
68: int ktrops(struct proc *, struct proc *, int, int, struct file *);
69: int ktrsetchildren(struct proc *, struct proc *, int, int,
70: struct file *);
71: int ktrwrite(struct proc *, struct ktr_header *);
72: int ktrcanset(struct proc *, struct proc *);
73: int ktrsamefile(struct file *, struct file *);
1.44 sommerfe 74:
75: /*
76: * "deep" compare of two files for the purposes of clearing a trace.
77: * Returns true if they're the same open file, or if they point at the
78: * same underlying vnode/socket.
79: */
80:
81: int
1.62 manu 82: ktrsamefile(f1, f2)
83: struct file *f1;
84: struct file *f2;
1.44 sommerfe 85: {
86: return ((f1 == f2) ||
1.45 sommerfe 87: ((f1 != NULL) && (f2 != NULL) &&
88: (f1->f_type == f2->f_type) &&
1.44 sommerfe 89: (f1->f_data == f2->f_data)));
90: }
1.22 christos 91:
1.28 christos 92: void
1.62 manu 93: ktrderef(p)
94: struct proc *p;
1.28 christos 95: {
1.42 sommerfe 96: struct file *fp = p->p_tracep;
97: p->p_traceflag = 0;
98: if (fp == NULL)
1.28 christos 99: return;
1.42 sommerfe 100: FILE_USE(fp);
1.59 jdolecek 101:
102: /*
103: * ktrace file descriptor can't be watched (are not visible to
104: * userspace), so no kqueue stuff here
105: */
1.42 sommerfe 106: closef(fp, NULL);
1.28 christos 107:
108: p->p_tracep = NULL;
109: }
110:
111: void
1.62 manu 112: ktradref(p)
113: struct proc *p;
1.28 christos 114: {
1.42 sommerfe 115: struct file *fp = p->p_tracep;
1.28 christos 116:
1.42 sommerfe 117: fp->f_count++;
1.28 christos 118: }
119:
1.39 thorpej 120: void
1.62 manu 121: ktrinitheader(kth, p, type)
122: struct ktr_header *kth;
123: struct proc *p;
124: int type;
1.1 cgd 125: {
126:
1.39 thorpej 127: memset(kth, 0, sizeof(*kth));
1.1 cgd 128: kth->ktr_type = type;
129: microtime(&kth->ktr_time);
130: kth->ktr_pid = p->p_pid;
1.32 perry 131: memcpy(kth->ktr_comm, p->p_comm, MAXCOMLEN);
1.1 cgd 132: }
133:
1.17 cgd 134: void
1.62 manu 135: ktrsyscall(p, code, realcode, args)
136: struct proc *p;
137: register_t code;
138: register_t realcode;
139: register_t args[];
1.1 cgd 140: {
1.39 thorpej 141: struct ktr_header kth;
142: struct ktr_syscall *ktp;
1.17 cgd 143: register_t *argp;
1.57 fvdl 144: int argsize;
145: size_t len;
1.60 thorpej 146: u_int i;
1.57 fvdl 147:
148: argsize = p->p_emul->e_sysent[code].sy_narg * sizeof (register_t);
149: len = sizeof(struct ktr_syscall) + argsize;
1.1 cgd 150:
1.9 cgd 151: p->p_traceflag |= KTRFAC_ACTIVE;
1.39 thorpej 152: ktrinitheader(&kth, p, KTR_SYSCALL);
153: ktp = malloc(len, M_TEMP, M_WAITOK);
1.61 manu 154: ktp->ktr_code = realcode;
1.17 cgd 155: ktp->ktr_argsize = argsize;
156: argp = (register_t *)((char *)ktp + sizeof(struct ktr_syscall));
1.31 perry 157: for (i = 0; i < (argsize / sizeof(*argp)); i++)
1.1 cgd 158: *argp++ = args[i];
1.39 thorpej 159: kth.ktr_buf = (caddr_t)ktp;
160: kth.ktr_len = len;
1.42 sommerfe 161: (void) ktrwrite(p, &kth);
1.39 thorpej 162: free(ktp, M_TEMP);
1.9 cgd 163: p->p_traceflag &= ~KTRFAC_ACTIVE;
1.1 cgd 164: }
165:
1.17 cgd 166: void
1.62 manu 167: ktrsysret(p, code, error, retval)
168: struct proc *p;
169: register_t code;
170: int error;
171: register_t retval;
1.1 cgd 172: {
1.39 thorpej 173: struct ktr_header kth;
1.1 cgd 174: struct ktr_sysret ktp;
175:
1.9 cgd 176: p->p_traceflag |= KTRFAC_ACTIVE;
1.39 thorpej 177: ktrinitheader(&kth, p, KTR_SYSRET);
1.1 cgd 178: ktp.ktr_code = code;
1.34 kleink 179: ktp.ktr_eosys = 0; /* XXX unused */
1.1 cgd 180: ktp.ktr_error = error;
181: ktp.ktr_retval = retval; /* what about val2 ? */
182:
1.39 thorpej 183: kth.ktr_buf = (caddr_t)&ktp;
184: kth.ktr_len = sizeof(struct ktr_sysret);
1.1 cgd 185:
1.42 sommerfe 186: (void) ktrwrite(p, &kth);
1.9 cgd 187: p->p_traceflag &= ~KTRFAC_ACTIVE;
1.1 cgd 188: }
189:
1.17 cgd 190: void
1.62 manu 191: ktrnamei(p, path)
192: struct proc *p;
193: char *path;
1.1 cgd 194: {
1.39 thorpej 195: struct ktr_header kth;
1.1 cgd 196:
1.9 cgd 197: p->p_traceflag |= KTRFAC_ACTIVE;
1.39 thorpej 198: ktrinitheader(&kth, p, KTR_NAMEI);
199: kth.ktr_len = strlen(path);
200: kth.ktr_buf = path;
1.18 christos 201:
1.42 sommerfe 202: (void) ktrwrite(p, &kth);
1.18 christos 203: p->p_traceflag &= ~KTRFAC_ACTIVE;
204: }
205:
206: void
1.62 manu 207: ktremul(p)
208: struct proc *p;
1.18 christos 209: {
1.39 thorpej 210: struct ktr_header kth;
1.50 scw 211: const char *emul = p->p_emul->e_name;
1.18 christos 212:
213: p->p_traceflag |= KTRFAC_ACTIVE;
1.39 thorpej 214: ktrinitheader(&kth, p, KTR_EMUL);
215: kth.ktr_len = strlen(emul);
1.50 scw 216: kth.ktr_buf = (caddr_t)emul;
1.1 cgd 217:
1.42 sommerfe 218: (void) ktrwrite(p, &kth);
1.9 cgd 219: p->p_traceflag &= ~KTRFAC_ACTIVE;
1.1 cgd 220: }
221:
1.17 cgd 222: void
1.62 manu 223: ktrgenio(p, fd, rw, iov, len, error)
224: struct proc *p;
225: int fd;
226: enum uio_rw rw;
227: struct iovec *iov;
228: int len;
229: int error;
1.1 cgd 230: {
1.39 thorpej 231: struct ktr_header kth;
1.28 christos 232: struct ktr_genio *ktp;
233: caddr_t cp;
234: int resid = len, cnt;
1.39 thorpej 235: int buflen;
236:
1.1 cgd 237: if (error)
238: return;
1.39 thorpej 239:
1.9 cgd 240: p->p_traceflag |= KTRFAC_ACTIVE;
1.39 thorpej 241:
242: buflen = min(PAGE_SIZE, len + sizeof(struct ktr_genio));
243:
244: ktrinitheader(&kth, p, KTR_GENIO);
245: ktp = malloc(buflen, M_TEMP, M_WAITOK);
1.1 cgd 246: ktp->ktr_fd = fd;
247: ktp->ktr_rw = rw;
1.39 thorpej 248:
249: kth.ktr_buf = (caddr_t)ktp;
250:
1.31 perry 251: cp = (caddr_t)((char *)ktp + sizeof(struct ktr_genio));
1.39 thorpej 252: buflen -= sizeof(struct ktr_genio);
253:
1.1 cgd 254: while (resid > 0) {
1.46 thorpej 255: KDASSERT(p->p_cpu != NULL);
256: KDASSERT(p->p_cpu == curcpu());
257: if (p->p_cpu->ci_schedstate.spc_flags & SPCF_SHOULDYIELD)
1.39 thorpej 258: preempt(NULL);
259:
260: cnt = min(iov->iov_len, buflen);
261: if (cnt > resid)
1.1 cgd 262: cnt = resid;
1.39 thorpej 263: if (copyin(iov->iov_base, cp, cnt))
264: break;
265:
266: kth.ktr_len = cnt + sizeof(struct ktr_genio);
267:
1.42 sommerfe 268: if (__predict_false(ktrwrite(p, &kth) != 0))
1.39 thorpej 269: break;
270:
271: iov->iov_base = (caddr_t)iov->iov_base + cnt;
272: iov->iov_len -= cnt;
273:
274: if (iov->iov_len == 0)
275: iov++;
276:
1.1 cgd 277: resid -= cnt;
278: }
279:
1.39 thorpej 280: free(ktp, M_TEMP);
1.9 cgd 281: p->p_traceflag &= ~KTRFAC_ACTIVE;
1.1 cgd 282: }
283:
1.17 cgd 284: void
1.62 manu 285: ktrpsig(p, sig, action, mask, code)
286: struct proc *p;
287: int sig;
288: sig_t action;
289: sigset_t *mask;
290: int code;
1.1 cgd 291: {
1.39 thorpej 292: struct ktr_header kth;
1.1 cgd 293: struct ktr_psig kp;
294:
1.9 cgd 295: p->p_traceflag |= KTRFAC_ACTIVE;
1.39 thorpej 296: ktrinitheader(&kth, p, KTR_PSIG);
1.1 cgd 297: kp.signo = (char)sig;
298: kp.action = action;
1.33 mycroft 299: kp.mask = *mask;
1.1 cgd 300: kp.code = code;
1.39 thorpej 301: kth.ktr_buf = (caddr_t)&kp;
302: kth.ktr_len = sizeof(struct ktr_psig);
1.1 cgd 303:
1.42 sommerfe 304: (void) ktrwrite(p, &kth);
1.9 cgd 305: p->p_traceflag &= ~KTRFAC_ACTIVE;
306: }
307:
1.17 cgd 308: void
1.62 manu 309: ktrcsw(p, out, user)
310: struct proc *p;
311: int out;
312: int user;
1.9 cgd 313: {
1.39 thorpej 314: struct ktr_header kth;
315: struct ktr_csw kc;
1.9 cgd 316:
317: p->p_traceflag |= KTRFAC_ACTIVE;
1.39 thorpej 318: ktrinitheader(&kth, p, KTR_CSW);
1.9 cgd 319: kc.out = out;
320: kc.user = user;
1.39 thorpej 321: kth.ktr_buf = (caddr_t)&kc;
322: kth.ktr_len = sizeof(struct ktr_csw);
1.9 cgd 323:
1.42 sommerfe 324: (void) ktrwrite(p, &kth);
1.9 cgd 325: p->p_traceflag &= ~KTRFAC_ACTIVE;
1.1 cgd 326: }
327:
1.51 jdolecek 328: void
329: ktruser(p, id, addr, len, ustr)
330: struct proc *p;
331: const char *id;
332: void *addr;
333: size_t len;
334: int ustr;
335: {
336: struct ktr_header kth;
337: struct ktr_user *ktp;
338: caddr_t user_dta;
339:
340: p->p_traceflag |= KTRFAC_ACTIVE;
341: ktrinitheader(&kth, p, KTR_USER);
342: ktp = malloc(sizeof(struct ktr_user) + len, M_TEMP, M_WAITOK);
343: if (ustr) {
344: if (copyinstr(id, ktp->ktr_id, KTR_USER_MAXIDLEN, NULL) != 0)
345: ktp->ktr_id[0] = '\0';
346: } else
347: strncpy(ktp->ktr_id, id, KTR_USER_MAXIDLEN);
348: ktp->ktr_id[KTR_USER_MAXIDLEN-1] = '\0';
349:
350: user_dta = (caddr_t) ((char *)ktp + sizeof(struct ktr_user));
351: if (copyin(addr, (void *) user_dta, len) != 0)
352: len = 0;
353:
354: kth.ktr_buf = (void *)ktp;
355: kth.ktr_len = sizeof(struct ktr_user) + len;
356: (void) ktrwrite(p, &kth);
357:
358: free(ktp, M_TEMP);
359: p->p_traceflag &= ~KTRFAC_ACTIVE;
360:
361: }
362:
1.62 manu 363: void
364: ktrmmsg(p, msgh, size)
365: struct proc *p;
1.63 ! christos 366: const void *msgh;
1.62 manu 367: size_t size;
368: {
369: struct ktr_header kth;
370: struct ktr_mmsg *kp;
371: int error;
372:
373: p->p_traceflag |= KTRFAC_ACTIVE;
374: ktrinitheader(&kth, p, KTR_MMSG);
375:
376: kp = (struct ktr_mmsg *)malloc(size, M_TEMP, M_WAITOK);
377: if ((error = copyin(msgh, kp, size)) != 0)
378: size = 0; /* Still log a message, but empty */
379:
380: kth.ktr_buf = (caddr_t)kp;
381: kth.ktr_len = size;
382: (void) ktrwrite(p, &kth);
383: free(kp, M_TEMP);
384: p->p_traceflag &= ~KTRFAC_ACTIVE;
385: }
386:
1.1 cgd 387: /* Interface and common routines */
388:
1.17 cgd 389: int
1.62 manu 390: ktrace_common(curp, ops, facs, pid, fp)
391: struct proc *curp;
392: int ops;
393: int facs;
394: int pid;
395: struct file *fp;
1.28 christos 396: {
1.42 sommerfe 397: int ret = 0;
398: int error = 0;
399: int one = 1;
400: int descend;
1.28 christos 401: struct proc *p;
402: struct pgrp *pg;
403:
404: curp->p_traceflag |= KTRFAC_ACTIVE;
1.42 sommerfe 405: descend = ops & KTRFLAG_DESCEND;
406: facs = facs & ~((unsigned) KTRFAC_ROOT);
1.28 christos 407:
408: /*
409: * Clear all uses of the tracefile
410: */
411: if (KTROP(ops) == KTROP_CLEARFILE) {
1.37 thorpej 412: proclist_lock_read();
1.39 thorpej 413: for (p = LIST_FIRST(&allproc); p != NULL;
414: p = LIST_NEXT(p, p_list)) {
1.44 sommerfe 415: if (ktrsamefile(p->p_tracep, fp)) {
1.28 christos 416: if (ktrcanset(curp, p))
417: ktrderef(p);
418: else
419: error = EPERM;
420: }
421: }
1.36 thorpej 422: proclist_unlock_read();
1.28 christos 423: goto done;
424: }
1.42 sommerfe 425:
426: /*
427: * Mark fp non-blocking, to avoid problems from possible deadlocks.
428: */
429:
1.43 sommerfe 430: if (fp != NULL) {
431: fp->f_flag |= FNONBLOCK;
432: (*fp->f_ops->fo_ioctl)(fp, FIONBIO, (caddr_t)&one, curp);
433: }
1.42 sommerfe 434:
1.28 christos 435: /*
436: * need something to (un)trace (XXX - why is this here?)
437: */
438: if (!facs) {
439: error = EINVAL;
440: goto done;
441: }
442: /*
443: * do it
444: */
1.42 sommerfe 445: if (pid < 0) {
1.28 christos 446: /*
447: * by process group
448: */
1.42 sommerfe 449: pg = pgfind(-pid);
1.28 christos 450: if (pg == NULL) {
451: error = ESRCH;
452: goto done;
453: }
1.39 thorpej 454: for (p = LIST_FIRST(&pg->pg_members); p != NULL;
455: p = LIST_NEXT(p, p_pglist)) {
1.28 christos 456: if (descend)
457: ret |= ktrsetchildren(curp, p, ops, facs, fp);
458: else
459: ret |= ktrops(curp, p, ops, facs, fp);
1.39 thorpej 460: }
1.28 christos 461:
462: } else {
463: /*
464: * by pid
465: */
1.42 sommerfe 466: p = pfind(pid);
1.28 christos 467: if (p == NULL) {
468: error = ESRCH;
469: goto done;
470: }
471: if (descend)
472: ret |= ktrsetchildren(curp, p, ops, facs, fp);
473: else
474: ret |= ktrops(curp, p, ops, facs, fp);
475: }
476: if (!ret)
477: error = EPERM;
478: done:
479: curp->p_traceflag &= ~KTRFAC_ACTIVE;
480: return (error);
481: }
482:
483: /*
484: * ktrace system call
485: */
486: /* ARGSUSED */
487: int
1.62 manu 488: sys_fktrace(curp, v, retval)
489: struct proc *curp;
490: void *v;
491: register_t *retval;
1.42 sommerfe 492: {
493: struct sys_fktrace_args /* {
494: syscallarg(int) fd;
495: syscallarg(int) ops;
496: syscallarg(int) facs;
497: syscallarg(int) pid;
498: } */ *uap = v;
499: struct file *fp = NULL;
500: struct filedesc *fdp = curp->p_fd;
501:
1.54 thorpej 502: if ((fp = fd_getfile(fdp, SCARG(uap, fd))) == NULL)
503: return (EBADF);
504:
505: if ((fp->f_flag & FWRITE) == 0)
1.42 sommerfe 506: return (EBADF);
507:
508: return ktrace_common(curp, SCARG(uap, ops),
509: SCARG(uap, facs), SCARG(uap, pid), fp);
510: }
511:
512: /*
513: * ktrace system call
514: */
515: /* ARGSUSED */
516: int
1.62 manu 517: sys_ktrace(curp, v, retval)
518: struct proc *curp;
519: void *v;
520: register_t *retval;
1.19 thorpej 521: {
1.28 christos 522: struct sys_ktrace_args /* {
1.24 mycroft 523: syscallarg(const char *) fname;
1.13 cgd 524: syscallarg(int) ops;
525: syscallarg(int) facs;
526: syscallarg(int) pid;
1.19 thorpej 527: } */ *uap = v;
1.28 christos 528: struct vnode *vp = NULL;
1.42 sommerfe 529: struct file *fp = NULL;
530: int fd;
531: int ops = SCARG(uap, ops);
1.1 cgd 532: int error = 0;
533: struct nameidata nd;
534:
1.42 sommerfe 535: ops = KTROP(ops) | (ops & KTRFLAG_DESCEND);
536:
1.9 cgd 537: curp->p_traceflag |= KTRFAC_ACTIVE;
1.1 cgd 538: if (ops != KTROP_CLEAR) {
539: /*
540: * an operation which requires a file argument.
541: */
1.13 cgd 542: NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, fname),
543: curp);
1.22 christos 544: if ((error = vn_open(&nd, FREAD|FWRITE, 0)) != 0) {
1.9 cgd 545: curp->p_traceflag &= ~KTRFAC_ACTIVE;
1.1 cgd 546: return (error);
1.9 cgd 547: }
1.1 cgd 548: vp = nd.ni_vp;
1.25 fvdl 549: VOP_UNLOCK(vp, 0);
1.1 cgd 550: if (vp->v_type != VREG) {
551: (void) vn_close(vp, FREAD|FWRITE, curp->p_ucred, curp);
1.9 cgd 552: curp->p_traceflag &= ~KTRFAC_ACTIVE;
1.1 cgd 553: return (EACCES);
554: }
555: /*
1.42 sommerfe 556: * XXX This uses up a file descriptor slot in the
557: * tracing process for the duration of this syscall.
558: * This is not expected to be a problem. If
559: * falloc(NULL, ...) DTRT we could skip that part, but
560: * that would require changing its interface to allow
561: * the caller to pass in a ucred..
562: *
563: * This will FILE_USE the fp it returns, if any.
564: * Keep it in use until we return.
1.1 cgd 565: */
1.42 sommerfe 566: if ((error = falloc(curp, &fp, &fd)) != 0)
1.1 cgd 567: goto done;
1.42 sommerfe 568:
569: fp->f_flag = FWRITE|FAPPEND;
570: fp->f_type = DTYPE_VNODE;
571: fp->f_ops = &vnops;
572: fp->f_data = (caddr_t)vp;
1.54 thorpej 573: FILE_SET_MATURE(fp);
1.42 sommerfe 574: vp = NULL;
575: }
576: error = ktrace_common(curp, SCARG(uap, ops), SCARG(uap, facs),
577: SCARG(uap, pid), fp);
578: done:
1.1 cgd 579: if (vp != NULL)
580: (void) vn_close(vp, FWRITE, curp->p_ucred, curp);
1.42 sommerfe 581: if (fp != NULL) {
1.44 sommerfe 582: FILE_UNUSE(fp, curp); /* release file */
1.42 sommerfe 583: fdrelease(curp, fd); /* release fd table slot */
584: }
1.1 cgd 585: return (error);
586: }
587:
1.4 andrew 588: int
1.62 manu 589: ktrops(curp, p, ops, facs, fp)
590: struct proc *curp;
591: struct proc *p;
592: int ops;
593: int facs;
594: struct file *fp;
1.1 cgd 595: {
596:
597: if (!ktrcanset(curp, p))
598: return (0);
1.28 christos 599: if (KTROP(ops) == KTROP_SET) {
1.42 sommerfe 600: if (p->p_tracep != fp) {
1.1 cgd 601: /*
602: * if trace file already in use, relinquish
603: */
1.28 christos 604: ktrderef(p);
1.42 sommerfe 605: p->p_tracep = fp;
1.28 christos 606: ktradref(p);
1.1 cgd 607: }
608: p->p_traceflag |= facs;
609: if (curp->p_ucred->cr_uid == 0)
610: p->p_traceflag |= KTRFAC_ROOT;
611: } else {
612: /* KTROP_CLEAR */
613: if (((p->p_traceflag &= ~facs) & KTRFAC_MASK) == 0) {
614: /* no more tracing */
1.28 christos 615: ktrderef(p);
1.1 cgd 616: }
617: }
1.21 christos 618:
619: /*
620: * Emit an emulation record, every time there is a ktrace
621: * change/attach request.
622: */
623: if (KTRPOINT(p, KTR_EMUL))
1.42 sommerfe 624: ktremul(p);
1.49 martin 625: #ifdef __HAVE_SYSCALL_INTERN
1.48 mycroft 626: (*p->p_emul->e_syscall_intern)(p);
1.49 martin 627: #endif
1.1 cgd 628:
629: return (1);
630: }
631:
1.22 christos 632: int
1.62 manu 633: ktrsetchildren(curp, top, ops, facs, fp)
634: struct proc *curp;
635: struct proc *top;
636: int ops;
637: int facs;
638: struct file *fp;
1.1 cgd 639: {
1.28 christos 640: struct proc *p;
641: int ret = 0;
1.1 cgd 642:
643: p = top;
644: for (;;) {
1.42 sommerfe 645: ret |= ktrops(curp, p, ops, facs, fp);
1.1 cgd 646: /*
647: * If this process has children, descend to them next,
648: * otherwise do any siblings, and if done with this level,
649: * follow back up the tree (but not past top).
650: */
1.39 thorpej 651: if (LIST_FIRST(&p->p_children) != NULL)
652: p = LIST_FIRST(&p->p_children);
1.1 cgd 653: else for (;;) {
654: if (p == top)
655: return (ret);
1.39 thorpej 656: if (LIST_NEXT(p, p_sibling) != NULL) {
657: p = LIST_NEXT(p, p_sibling);
1.1 cgd 658: break;
659: }
1.12 mycroft 660: p = p->p_pptr;
1.1 cgd 661: }
662: }
663: /*NOTREACHED*/
664: }
665:
1.39 thorpej 666: int
1.62 manu 667: ktrwrite(p, kth)
668: struct proc *p;
669: struct ktr_header *kth;
1.1 cgd 670: {
671: struct uio auio;
672: struct iovec aiov[2];
1.42 sommerfe 673: int error, tries;
674: struct file *fp = p->p_tracep;
1.1 cgd 675:
1.42 sommerfe 676: if (fp == NULL)
677: return 0;
678:
1.1 cgd 679: auio.uio_iov = &aiov[0];
680: auio.uio_offset = 0;
681: auio.uio_segflg = UIO_SYSSPACE;
682: auio.uio_rw = UIO_WRITE;
683: aiov[0].iov_base = (caddr_t)kth;
684: aiov[0].iov_len = sizeof(struct ktr_header);
685: auio.uio_resid = sizeof(struct ktr_header);
686: auio.uio_iovcnt = 1;
687: auio.uio_procp = (struct proc *)0;
688: if (kth->ktr_len > 0) {
689: auio.uio_iovcnt++;
690: aiov[1].iov_base = kth->ktr_buf;
691: aiov[1].iov_len = kth->ktr_len;
692: auio.uio_resid += kth->ktr_len;
693: }
1.28 christos 694:
1.42 sommerfe 695: FILE_USE(fp);
696:
697: tries = 0;
698: do {
1.30 thorpej 699: error = (*fp->f_ops->fo_write)(fp, &fp->f_offset, &auio,
700: fp->f_cred, FOF_UPDATE_OFFSET);
1.42 sommerfe 701: tries++;
702: if (error == EWOULDBLOCK)
703: yield();
704: } while ((error == EWOULDBLOCK) && (tries < 3));
705: FILE_UNUSE(fp, NULL);
1.28 christos 706:
1.40 thorpej 707: if (__predict_true(error == 0))
1.39 thorpej 708: return (0);
1.1 cgd 709: /*
1.38 darrenr 710: * If error encountered, give up tracing on this vnode. Don't report
711: * EPIPE as this can easily happen with fktrace()/ktruss.
1.1 cgd 712: */
1.38 darrenr 713: if (error != EPIPE)
714: log(LOG_NOTICE,
715: "ktrace write failed, errno %d, tracing stopped\n",
716: error);
1.37 thorpej 717: proclist_lock_read();
1.39 thorpej 718: for (p = LIST_FIRST(&allproc); p != NULL; p = LIST_NEXT(p, p_list)) {
1.44 sommerfe 719: if (ktrsamefile(p->p_tracep, fp))
1.28 christos 720: ktrderef(p);
1.1 cgd 721: }
1.36 thorpej 722: proclist_unlock_read();
1.39 thorpej 723:
724: return (error);
1.1 cgd 725: }
726:
727: /*
728: * Return true if caller has permission to set the ktracing state
729: * of target. Essentially, the target can't possess any
730: * more permissions than the caller. KTRFAC_ROOT signifies that
731: * root previously set the tracing status on the target process, and
732: * so, only root may further change it.
733: *
734: * TODO: check groups. use caller effective gid.
735: */
1.22 christos 736: int
1.62 manu 737: ktrcanset(callp, targetp)
738: struct proc *callp;
739: struct proc *targetp;
1.1 cgd 740: {
1.28 christos 741: struct pcred *caller = callp->p_cred;
742: struct pcred *target = targetp->p_cred;
1.1 cgd 743:
744: if ((caller->pc_ucred->cr_uid == target->p_ruid &&
745: target->p_ruid == target->p_svuid &&
746: caller->p_rgid == target->p_rgid && /* XXX */
747: target->p_rgid == target->p_svgid &&
1.58 itojun 748: (targetp->p_traceflag & KTRFAC_ROOT) == 0 &&
749: (targetp->p_flag & P_SUGID) == 0) ||
1.1 cgd 750: caller->pc_ucred->cr_uid == 0)
751: return (1);
752:
753: return (0);
754: }
1.47 thorpej 755: #endif /* KTRACE */
1.51 jdolecek 756:
757: /*
758: * Put user defined entry to ktrace records.
759: */
760: int
761: sys_utrace(p, v, retval)
762: struct proc *p;
763: void *v;
764: register_t *retval;
765: {
766: #ifdef KTRACE
767: struct sys_utrace_args /* {
1.52 jdolecek 768: syscallarg(const char *) label;
1.51 jdolecek 769: syscallarg(void *) addr;
770: syscallarg(size_t) len;
771: } */ *uap = v;
772:
773: if (!KTRPOINT(p, KTR_USER))
774: return (0);
1.53 jdolecek 775:
776: if (SCARG(uap, len) > KTR_USER_MAXLEN)
777: return (EINVAL);
1.51 jdolecek 778:
1.52 jdolecek 779: ktruser(p, SCARG(uap, label), SCARG(uap, addr), SCARG(uap, len), 1);
1.51 jdolecek 780:
781: return (0);
782: #else /* !KTRACE */
783: return ENOSYS;
784: #endif /* KTRACE */
785: }
CVSweb <webmaster@jp.NetBSD.org>