Annotation of sys/kern/kern_ktrace.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: kern_ktrace.c,v 1.42 2007/05/16 17:27:30 art Exp $ */
2: /* $NetBSD: kern_ktrace.c,v 1.23 1996/02/09 18:59:36 christos Exp $ */
3:
4: /*
5: * Copyright (c) 1989, 1993
6: * The Regents of the University of California. All rights reserved.
7: *
8: * Redistribution and use in source and binary forms, with or without
9: * modification, are permitted provided that the following conditions
10: * are met:
11: * 1. Redistributions of source code must retain the above copyright
12: * notice, this list of conditions and the following disclaimer.
13: * 2. Redistributions in binary form must reproduce the above copyright
14: * notice, this list of conditions and the following disclaimer in the
15: * documentation and/or other materials provided with the distribution.
16: * 3. Neither the name of the University nor the names of its contributors
17: * may be used to endorse or promote products derived from this software
18: * without specific prior written permission.
19: *
20: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30: * SUCH DAMAGE.
31: *
32: * @(#)kern_ktrace.c 8.2 (Berkeley) 9/23/93
33: */
34:
35: #ifdef KTRACE
36:
37: #include <sys/param.h>
38: #include <sys/systm.h>
39: #include <sys/proc.h>
40: #include <sys/sched.h>
41: #include <sys/file.h>
42: #include <sys/namei.h>
43: #include <sys/vnode.h>
44: #include <sys/ktrace.h>
45: #include <sys/malloc.h>
46: #include <sys/syslog.h>
47: #include <sys/sysctl.h>
48:
49: #include <sys/mount.h>
50: #include <sys/syscall.h>
51: #include <sys/syscallargs.h>
52:
53: #include <uvm/uvm_extern.h>
54:
55: void ktrinitheader(struct ktr_header *, struct proc *, int);
56: int ktrops(struct proc *, struct proc *, int, int, struct vnode *);
57: int ktrsetchildren(struct proc *, struct proc *, int, int,
58: struct vnode *);
59: int ktrwrite(struct proc *, struct ktr_header *);
60: int ktrcanset(struct proc *, struct proc *);
61:
62: /*
63: * Change the trace vnode in a correct way (to avoid races).
64: */
65: void
66: ktrsettracevnode(struct proc *p, struct vnode *newvp)
67: {
68: struct vnode *vp;
69:
70: if (p->p_tracep == newvp) /* avoid work */
71: return;
72:
73: if (newvp != NULL)
74: VREF(newvp);
75:
76: vp = p->p_tracep;
77: p->p_tracep = newvp;
78:
79: if (vp != NULL)
80: vrele(vp);
81: }
82:
83: void
84: ktrinitheader(struct ktr_header *kth, struct proc *p, int type)
85: {
86: bzero(kth, sizeof (struct ktr_header));
87: kth->ktr_type = type;
88: microtime(&kth->ktr_time);
89: kth->ktr_pid = p->p_pid;
90: bcopy(p->p_comm, kth->ktr_comm, MAXCOMLEN);
91: }
92:
93: void
94: ktrsyscall(struct proc *p, register_t code, size_t argsize, register_t args[])
95: {
96: struct ktr_header kth;
97: struct ktr_syscall *ktp;
98: size_t len = sizeof(struct ktr_syscall) + argsize;
99: register_t *argp;
100: u_int nargs = 0;
101: int i;
102:
103: if (code == SYS___sysctl && (p->p_emul->e_flags & EMUL_NATIVE)) {
104: /*
105: * The native sysctl encoding stores the mib[]
106: * array because it is interesting.
107: */
108: if (args[1] > 0)
109: nargs = min(args[1], CTL_MAXNAME);
110: len += nargs * sizeof(int);
111: }
112: p->p_traceflag |= KTRFAC_ACTIVE;
113: ktrinitheader(&kth, p, KTR_SYSCALL);
114: ktp = malloc(len, M_TEMP, M_WAITOK);
115: ktp->ktr_code = code;
116: ktp->ktr_argsize = argsize;
117: argp = (register_t *)((char *)ktp + sizeof(struct ktr_syscall));
118: for (i = 0; i < (argsize / sizeof *argp); i++)
119: *argp++ = args[i];
120: if (code == SYS___sysctl && (p->p_emul->e_flags & EMUL_NATIVE) &&
121: nargs &&
122: copyin((void *)args[0], argp, nargs * sizeof(int)))
123: bzero(argp, nargs * sizeof(int));
124: kth.ktr_buf = (caddr_t)ktp;
125: kth.ktr_len = len;
126: ktrwrite(p, &kth);
127: free(ktp, M_TEMP);
128: p->p_traceflag &= ~KTRFAC_ACTIVE;
129: }
130:
131: void
132: ktrsysret(struct proc *p, register_t code, int error, register_t retval)
133: {
134: struct ktr_header kth;
135: struct ktr_sysret ktp;
136:
137: p->p_traceflag |= KTRFAC_ACTIVE;
138: ktrinitheader(&kth, p, KTR_SYSRET);
139: ktp.ktr_code = code;
140: ktp.ktr_error = error;
141: ktp.ktr_retval = retval; /* what about val2 ? */
142:
143: kth.ktr_buf = (caddr_t)&ktp;
144: kth.ktr_len = sizeof(struct ktr_sysret);
145:
146: ktrwrite(p, &kth);
147: p->p_traceflag &= ~KTRFAC_ACTIVE;
148: }
149:
150: void
151: ktrnamei(struct proc *p, char *path)
152: {
153: struct ktr_header kth;
154:
155: p->p_traceflag |= KTRFAC_ACTIVE;
156: ktrinitheader(&kth, p, KTR_NAMEI);
157: kth.ktr_len = strlen(path);
158: kth.ktr_buf = path;
159:
160: ktrwrite(p, &kth);
161: p->p_traceflag &= ~KTRFAC_ACTIVE;
162: }
163:
164: void
165: ktremul(struct proc *p, char *emul)
166: {
167: struct ktr_header kth;
168:
169: p->p_traceflag |= KTRFAC_ACTIVE;
170: ktrinitheader(&kth, p, KTR_EMUL);
171: kth.ktr_len = strlen(emul);
172: kth.ktr_buf = emul;
173:
174: ktrwrite(p, &kth);
175: p->p_traceflag &= ~KTRFAC_ACTIVE;
176: }
177:
178: void
179: ktrgenio(struct proc *p, int fd, enum uio_rw rw, struct iovec *iov, int len,
180: int error)
181: {
182: struct ktr_header kth;
183: struct ktr_genio *ktp;
184: caddr_t cp;
185: int resid = len, count;
186: int buflen;
187:
188: if (error)
189: return;
190:
191: p->p_traceflag |= KTRFAC_ACTIVE;
192:
193: buflen = min(PAGE_SIZE, len + sizeof(struct ktr_genio));
194:
195: ktrinitheader(&kth, p, KTR_GENIO);
196: ktp = malloc(buflen, M_TEMP, M_WAITOK);
197: ktp->ktr_fd = fd;
198: ktp->ktr_rw = rw;
199:
200: kth.ktr_buf = (caddr_t)ktp;
201:
202: cp = (caddr_t)((char *)ktp + sizeof (struct ktr_genio));
203: buflen -= sizeof(struct ktr_genio);
204:
205: while (resid > 0) {
206: /*
207: * Don't allow this process to hog the cpu when doing
208: * huge I/O.
209: */
210: if (curcpu()->ci_schedstate.spc_schedflags & SPCF_SHOULDYIELD)
211: preempt(NULL);
212:
213: count = min(iov->iov_len, buflen);
214: if (count > resid)
215: count = resid;
216: if (copyin(iov->iov_base, cp, count))
217: break;
218:
219: kth.ktr_len = count + sizeof(struct ktr_genio);
220:
221: if (ktrwrite(p, &kth) != 0)
222: break;
223:
224: iov->iov_len -= count;
225: iov->iov_base = (caddr_t)iov->iov_base + count;
226:
227: if (iov->iov_len == 0)
228: iov++;
229:
230: resid -= count;
231: }
232:
233: free(ktp, M_TEMP);
234: p->p_traceflag &= ~KTRFAC_ACTIVE;
235:
236: }
237:
238: void
239: ktrpsig(struct proc *p, int sig, sig_t action, int mask, int code,
240: siginfo_t *si)
241: {
242: struct ktr_header kth;
243: struct ktr_psig kp;
244:
245: p->p_traceflag |= KTRFAC_ACTIVE;
246: ktrinitheader(&kth, p, KTR_PSIG);
247: kp.signo = (char)sig;
248: kp.action = action;
249: kp.mask = mask;
250: kp.code = code;
251: kp.si = *si;
252: kth.ktr_buf = (caddr_t)&kp;
253: kth.ktr_len = sizeof(struct ktr_psig);
254:
255: ktrwrite(p, &kth);
256: p->p_traceflag &= ~KTRFAC_ACTIVE;
257: }
258:
259: void
260: ktrcsw(struct proc *p, int out, int user)
261: {
262: struct ktr_header kth;
263: struct ktr_csw kc;
264:
265: p->p_traceflag |= KTRFAC_ACTIVE;
266: ktrinitheader(&kth, p, KTR_CSW);
267: kc.out = out;
268: kc.user = user;
269: kth.ktr_buf = (caddr_t)&kc;
270: kth.ktr_len = sizeof(struct ktr_csw);
271:
272: ktrwrite(p, &kth);
273: p->p_traceflag &= ~KTRFAC_ACTIVE;
274: }
275:
276: /* Interface and common routines */
277:
278: /*
279: * ktrace system call
280: */
281: /* ARGSUSED */
282: int
283: sys_ktrace(struct proc *curp, void *v, register_t *retval)
284: {
285: struct sys_ktrace_args /* {
286: syscallarg(const char *) fname;
287: syscallarg(int) ops;
288: syscallarg(int) facs;
289: syscallarg(pid_t) pid;
290: } */ *uap = v;
291: struct vnode *vp = NULL;
292: struct proc *p = NULL;
293: struct pgrp *pg;
294: int facs = SCARG(uap, facs) & ~((unsigned) KTRFAC_ROOT);
295: int ops = KTROP(SCARG(uap, ops));
296: int descend = SCARG(uap, ops) & KTRFLAG_DESCEND;
297: int ret = 0;
298: int error = 0;
299: struct nameidata nd;
300:
301: curp->p_traceflag |= KTRFAC_ACTIVE;
302: if (ops != KTROP_CLEAR) {
303: /*
304: * an operation which requires a file argument.
305: */
306: NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, fname),
307: curp);
308: if ((error = vn_open(&nd, FREAD|FWRITE|O_NOFOLLOW, 0)) != 0) {
309: curp->p_traceflag &= ~KTRFAC_ACTIVE;
310: return (error);
311: }
312: vp = nd.ni_vp;
313:
314: VOP_UNLOCK(vp, 0, curp);
315: if (vp->v_type != VREG) {
316: (void) vn_close(vp, FREAD|FWRITE, curp->p_ucred, curp);
317: curp->p_traceflag &= ~KTRFAC_ACTIVE;
318: return (EACCES);
319: }
320: }
321: /*
322: * Clear all uses of the tracefile
323: */
324: if (ops == KTROP_CLEARFILE) {
325: for (p = LIST_FIRST(&allproc); p; p = LIST_NEXT(p, p_list)) {
326: if (p->p_tracep == vp) {
327: if (ktrcanset(curp, p)) {
328: p->p_traceflag = 0;
329: ktrsettracevnode(p, NULL);
330: } else
331: error = EPERM;
332: }
333: }
334: goto done;
335: }
336: /*
337: * need something to (un)trace (XXX - why is this here?)
338: */
339: if (!facs) {
340: error = EINVAL;
341: goto done;
342: }
343: /*
344: * do it
345: */
346: if (SCARG(uap, pid) < 0) {
347: /*
348: * by process group
349: */
350: pg = pgfind(-SCARG(uap, pid));
351: if (pg == NULL) {
352: error = ESRCH;
353: goto done;
354: }
355: LIST_FOREACH(p, &pg->pg_members, p_pglist)
356: if (descend)
357: ret |= ktrsetchildren(curp, p, ops, facs, vp);
358: else
359: ret |= ktrops(curp, p, ops, facs, vp);
360:
361: } else {
362: /*
363: * by pid
364: */
365: p = pfind(SCARG(uap, pid));
366: if (p == NULL) {
367: error = ESRCH;
368: goto done;
369: }
370: if (descend)
371: ret |= ktrsetchildren(curp, p, ops, facs, vp);
372: else
373: ret |= ktrops(curp, p, ops, facs, vp);
374: }
375: if (!ret)
376: error = EPERM;
377: done:
378: if (vp != NULL)
379: (void) vn_close(vp, FWRITE, curp->p_ucred, curp);
380: curp->p_traceflag &= ~KTRFAC_ACTIVE;
381: return (error);
382: }
383:
384: int
385: ktrops(struct proc *curp, struct proc *p, int ops, int facs, struct vnode *vp)
386: {
387:
388: if (!ktrcanset(curp, p))
389: return (0);
390: if (ops == KTROP_SET) {
391: ktrsettracevnode(p, vp);
392: p->p_traceflag |= facs;
393: if (curp->p_ucred->cr_uid == 0)
394: p->p_traceflag |= KTRFAC_ROOT;
395: } else {
396: /* KTROP_CLEAR */
397: if (((p->p_traceflag &= ~facs) & KTRFAC_MASK) == 0) {
398: /* no more tracing */
399: p->p_traceflag = 0;
400: ktrsettracevnode(p, NULL);
401: }
402: }
403:
404: /*
405: * Emit an emulation record, every time there is a ktrace
406: * change/attach request.
407: */
408: if (KTRPOINT(p, KTR_EMUL))
409: ktremul(p, p->p_emul->e_name);
410:
411: return (1);
412: }
413:
414: int
415: ktrsetchildren(struct proc *curp, struct proc *top, int ops, int facs,
416: struct vnode *vp)
417: {
418: struct proc *p;
419: int ret = 0;
420:
421: p = top;
422: for (;;) {
423: ret |= ktrops(curp, p, ops, facs, vp);
424: /*
425: * If this process has children, descend to them next,
426: * otherwise do any siblings, and if done with this level,
427: * follow back up the tree (but not past top).
428: */
429: if (!LIST_EMPTY(&p->p_children))
430: p = LIST_FIRST(&p->p_children);
431: else for (;;) {
432: if (p == top)
433: return (ret);
434: if (LIST_NEXT(p, p_sibling) != NULL) {
435: p = LIST_NEXT(p, p_sibling);
436: break;
437: }
438: p = p->p_pptr;
439: }
440: }
441: /*NOTREACHED*/
442: }
443:
444: int
445: ktrwrite(struct proc *p, struct ktr_header *kth)
446: {
447: struct uio auio;
448: struct iovec aiov[2];
449: int error;
450: struct vnode *vp = p->p_tracep;
451:
452: if (vp == NULL)
453: return 0;
454: auio.uio_iov = &aiov[0];
455: auio.uio_offset = 0;
456: auio.uio_segflg = UIO_SYSSPACE;
457: auio.uio_rw = UIO_WRITE;
458: aiov[0].iov_base = (caddr_t)kth;
459: aiov[0].iov_len = sizeof(struct ktr_header);
460: auio.uio_resid = sizeof(struct ktr_header);
461: auio.uio_iovcnt = 1;
462: auio.uio_procp = p;
463: if (kth->ktr_len > 0) {
464: auio.uio_iovcnt++;
465: aiov[1].iov_base = kth->ktr_buf;
466: aiov[1].iov_len = kth->ktr_len;
467: auio.uio_resid += kth->ktr_len;
468: }
469: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
470: error = VOP_WRITE(vp, &auio, IO_UNIT|IO_APPEND, p->p_ucred);
471: VOP_UNLOCK(vp, 0, p);
472: if (!error)
473: return 0;
474: /*
475: * If error encountered, give up tracing on this vnode.
476: */
477: log(LOG_NOTICE, "ktrace write failed, errno %d, tracing stopped\n",
478: error);
479: for (p = LIST_FIRST(&allproc); p != NULL; p = LIST_NEXT(p, p_list)) {
480: if (p->p_tracep == vp) {
481: p->p_traceflag = 0;
482: ktrsettracevnode(p, NULL);
483: }
484: }
485:
486: return error;
487: }
488:
489: /*
490: * Return true if caller has permission to set the ktracing state
491: * of target. Essentially, the target can't possess any
492: * more permissions than the caller. KTRFAC_ROOT signifies that
493: * root previously set the tracing status on the target process, and
494: * so, only root may further change it.
495: *
496: * TODO: check groups. use caller effective gid.
497: */
498: int
499: ktrcanset(struct proc *callp, struct proc *targetp)
500: {
501: struct pcred *caller = callp->p_cred;
502: struct pcred *target = targetp->p_cred;
503:
504: if ((caller->pc_ucred->cr_uid == target->p_ruid &&
505: target->p_ruid == target->p_svuid &&
506: caller->p_rgid == target->p_rgid && /* XXX */
507: target->p_rgid == target->p_svgid &&
508: (targetp->p_traceflag & KTRFAC_ROOT) == 0 &&
509: !ISSET(targetp->p_flag, P_SUGID)) ||
510: caller->pc_ucred->cr_uid == 0)
511: return (1);
512:
513: return (0);
514: }
515:
516: #endif
CVSweb