]>
git.saurik.com Git - apple/xnu.git/blob - bsd/kern/kern_ktrace.c
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
22 /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
24 * Copyright (c) 1989, 1993
25 * The Regents of the University of California. All rights reserved.
27 * Redistribution and use in source and binary forms, with or without
28 * modification, are permitted provided that the following conditions
30 * 1. Redistributions of source code must retain the above copyright
31 * notice, this list of conditions and the following disclaimer.
32 * 2. Redistributions in binary form must reproduce the above copyright
33 * notice, this list of conditions and the following disclaimer in the
34 * documentation and/or other materials provided with the distribution.
35 * 3. All advertising materials mentioning features or use of this software
36 * must display the following acknowledgement:
37 * This product includes software developed by the University of
38 * California, Berkeley and its contributors.
39 * 4. Neither the name of the University nor the names of its contributors
40 * may be used to endorse or promote products derived from this software
41 * without specific prior written permission.
43 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
44 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
45 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
46 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
47 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
48 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
49 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
50 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
51 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
52 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
55 * @(#)kern_ktrace.c 8.2 (Berkeley) 9/23/93
59 #include <sys/param.h>
60 #include <sys/systm.h>
63 #include <sys/namei.h>
64 #include <sys/vnode.h>
65 #include <sys/ktrace.h>
66 #include <sys/malloc.h>
67 #include <sys/syslog.h>
69 #include <sys/mount.h>
77 register struct ktr_header
*kth
;
78 struct proc
*p
= current_proc(); /* XXX */
80 MALLOC(kth
, struct ktr_header
*, sizeof (struct ktr_header
),
83 microtime(&kth
->ktr_time
);
84 kth
->ktr_pid
= p
->p_pid
;
85 bcopy(p
->p_comm
, kth
->ktr_comm
, MAXCOMLEN
);
90 ktrsyscall(vp
, code
, argsize
, args
)
96 struct ktr_header
*kth
;
97 struct ktr_syscall
*ktp
;
98 register len
= sizeof(struct ktr_syscall
) + argsize
;
99 struct proc
*p
= current_proc(); /* XXX */
103 p
->p_traceflag
|= KTRFAC_ACTIVE
;
104 kth
= ktrgetheader(KTR_SYSCALL
);
105 MALLOC(ktp
, struct ktr_syscall
*, len
, M_TEMP
, M_WAITOK
);
106 ktp
->ktr_code
= code
;
107 ktp
->ktr_argsize
= argsize
;
108 argp
= (register_t
*)((char *)ktp
+ sizeof(struct ktr_syscall
));
109 for (i
= 0; i
< (argsize
/ sizeof *argp
); i
++)
111 kth
->ktr_buf
= (caddr_t
)ktp
;
116 p
->p_traceflag
&= ~KTRFAC_ACTIVE
;
120 ktrsysret(vp
, code
, error
, retval
)
126 struct ktr_header
*kth
;
127 struct ktr_sysret ktp
;
128 struct proc
*p
= current_proc(); /* XXX */
130 p
->p_traceflag
|= KTRFAC_ACTIVE
;
131 kth
= ktrgetheader(KTR_SYSRET
);
133 ktp
.ktr_error
= error
;
134 ktp
.ktr_retval
= retval
; /* what about val2 ? */
136 kth
->ktr_buf
= (caddr_t
)&ktp
;
137 kth
->ktr_len
= sizeof(struct ktr_sysret
);
141 p
->p_traceflag
&= ~KTRFAC_ACTIVE
;
149 struct ktr_header
*kth
;
150 struct proc
*p
= current_proc(); /* XXX */
152 p
->p_traceflag
|= KTRFAC_ACTIVE
;
153 kth
= ktrgetheader(KTR_NAMEI
);
154 kth
->ktr_len
= strlen(path
);
159 p
->p_traceflag
&= ~KTRFAC_ACTIVE
;
163 ktrgenio(vp
, fd
, rw
, iov
, len
, error
)
167 register struct iovec
*iov
;
170 struct ktr_header
*kth
;
171 register struct ktr_genio
*ktp
;
173 register int resid
= len
, cnt
;
174 struct proc
*p
= current_proc(); /* XXX */
178 p
->p_traceflag
|= KTRFAC_ACTIVE
;
179 kth
= ktrgetheader(KTR_GENIO
);
180 MALLOC(ktp
, struct ktr_genio
*, sizeof(struct ktr_genio
) + len
,
184 cp
= (caddr_t
)((char *)ktp
+ sizeof (struct ktr_genio
));
186 if ((cnt
= iov
->iov_len
) > resid
)
188 if (copyin(iov
->iov_base
, cp
, (unsigned)cnt
))
194 kth
->ktr_buf
= (caddr_t
)ktp
;
195 kth
->ktr_len
= sizeof (struct ktr_genio
) + len
;
201 p
->p_traceflag
&= ~KTRFAC_ACTIVE
;
205 ktrpsig(vp
, sig
, action
, mask
, code
)
211 struct ktr_header
*kth
;
213 struct proc
*p
= current_proc(); /* XXX */
215 p
->p_traceflag
|= KTRFAC_ACTIVE
;
216 kth
= ktrgetheader(KTR_PSIG
);
217 kp
.signo
= (char)sig
;
221 kth
->ktr_buf
= (caddr_t
)&kp
;
222 kth
->ktr_len
= sizeof (struct ktr_psig
);
226 p
->p_traceflag
&= ~KTRFAC_ACTIVE
;
230 ktrcsw(vp
, out
, user
)
234 struct ktr_header
*kth
;
236 struct proc
*p
= current_proc(); /* XXX */
238 p
->p_traceflag
|= KTRFAC_ACTIVE
;
239 kth
= ktrgetheader(KTR_CSW
);
242 kth
->ktr_buf
= (caddr_t
)&kc
;
243 kth
->ktr_len
= sizeof (struct ktr_csw
);
247 p
->p_traceflag
&= ~KTRFAC_ACTIVE
;
250 /* Interface and common routines */
263 ktrace(curp
, uap
, retval
)
265 register struct ktrace_args
*uap
;
268 register struct vnode
*vp
= NULL
;
269 register struct proc
*p
;
271 int facs
= SCARG(uap
, facs
) & ~KTRFAC_ROOT
;
272 int ops
= KTROP(SCARG(uap
, ops
));
273 int descend
= SCARG(uap
, ops
) & KTRFLAG_DESCEND
;
278 curp
->p_traceflag
|= KTRFAC_ACTIVE
;
279 if (ops
!= KTROP_CLEAR
) {
281 * an operation which requires a file argument.
283 NDINIT(&nd
, LOOKUP
, FOLLOW
, UIO_USERSPACE
, SCARG(uap
, fname
),
285 if (error
= vn_open(&nd
, FREAD
|FWRITE
, 0)) {
286 curp
->p_traceflag
&= ~KTRFAC_ACTIVE
;
290 VOP_UNLOCK(vp
, 0, p
);
291 if (vp
->v_type
!= VREG
) {
292 (void) vn_close(vp
, FREAD
|FWRITE
, curp
->p_ucred
, curp
);
293 curp
->p_traceflag
&= ~KTRFAC_ACTIVE
;
298 * Clear all uses of the tracefile
300 if (ops
== KTROP_CLEARFILE
) {
301 for (p
= allproc
.lh_first
; p
!= 0; p
= p
->p_list
.le_next
) {
302 if (p
->p_tracep
== vp
) {
303 if (ktrcanset(curp
, p
)) {
306 (void) vn_close(vp
, FREAD
|FWRITE
,
315 * need something to (un)trace (XXX - why is this here?)
324 if (SCARG(uap
, pid
) < 0) {
328 pg
= pgfind(-SCARG(uap
, pid
));
333 for (p
= pg
->pg_members
.lh_first
; p
!= 0; p
= p
->p_pglist
.le_next
)
335 ret
|= ktrsetchildren(curp
, p
, ops
, facs
, vp
);
337 ret
|= ktrops(curp
, p
, ops
, facs
, vp
);
343 p
= pfind(SCARG(uap
, pid
));
349 ret
|= ktrsetchildren(curp
, p
, ops
, facs
, vp
);
351 ret
|= ktrops(curp
, p
, ops
, facs
, vp
);
357 (void) vn_close(vp
, FWRITE
, curp
->p_ucred
, curp
);
358 curp
->p_traceflag
&= ~KTRFAC_ACTIVE
;
363 ktrops(curp
, p
, ops
, facs
, vp
)
364 struct proc
*p
, *curp
;
369 if (!ktrcanset(curp
, p
))
371 if (ops
== KTROP_SET
) {
372 if (p
->p_tracep
!= vp
) {
374 * if trace file already in use, relinquish
376 if (p
->p_tracep
!= NULL
)
381 p
->p_traceflag
|= facs
;
382 if (curp
->p_ucred
->cr_uid
== 0)
383 p
->p_traceflag
|= KTRFAC_ROOT
;
386 if (((p
->p_traceflag
&= ~facs
) & KTRFAC_MASK
) == 0) {
387 /* no more tracing */
389 if (p
->p_tracep
!= NULL
) {
399 ktrsetchildren(curp
, top
, ops
, facs
, vp
)
400 struct proc
*curp
, *top
;
404 register struct proc
*p
;
405 register int ret
= 0;
409 ret
|= ktrops(curp
, p
, ops
, facs
, vp
);
411 * If this process has children, descend to them next,
412 * otherwise do any siblings, and if done with this level,
413 * follow back up the tree (but not past top).
415 if (p
->p_children
.lh_first
)
416 p
= p
->p_children
.lh_first
;
420 if (p
->p_sibling
.le_next
) {
421 p
= p
->p_sibling
.le_next
;
432 register struct ktr_header
*kth
;
435 struct iovec aiov
[2];
436 register struct proc
*p
= current_proc(); /* XXX */
441 auio
.uio_iov
= &aiov
[0];
443 auio
.uio_segflg
= UIO_SYSSPACE
;
444 auio
.uio_rw
= UIO_WRITE
;
445 aiov
[0].iov_base
= (caddr_t
)kth
;
446 aiov
[0].iov_len
= sizeof(struct ktr_header
);
447 auio
.uio_resid
= sizeof(struct ktr_header
);
449 auio
.uio_procp
= (struct proc
*)0;
450 if (kth
->ktr_len
> 0) {
452 aiov
[1].iov_base
= kth
->ktr_buf
;
453 aiov
[1].iov_len
= kth
->ktr_len
;
454 auio
.uio_resid
+= kth
->ktr_len
;
456 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
457 error
= VOP_WRITE(vp
, &auio
, IO_UNIT
|IO_APPEND
, p
->p_ucred
);
458 VOP_UNLOCK(vp
, 0, p
);
462 * If error encountered, give up tracing on this vnode.
464 log(LOG_NOTICE
, "ktrace write failed, errno %d, tracing stopped\n",
466 for (p
= allproc
.lh_first
; p
!= 0; p
= p
->p_list
.le_next
) {
467 if (p
->p_tracep
== vp
) {
476 * Return true if caller has permission to set the ktracing state
477 * of target. Essentially, the target can't possess any
478 * more permissions than the caller. KTRFAC_ROOT signifies that
479 * root previously set the tracing status on the target process, and
480 * so, only root may further change it.
482 * TODO: check groups. use caller effective gid.
484 ktrcanset(callp
, targetp
)
485 struct proc
*callp
, *targetp
;
487 register struct pcred
*caller
= callp
->p_cred
;
488 register struct pcred
*target
= targetp
->p_cred
;
490 if ((caller
->pc_ucred
->cr_uid
== target
->p_ruid
&&
491 target
->p_ruid
== target
->p_svuid
&&
492 caller
->p_rgid
== target
->p_rgid
&& /* XXX */
493 target
->p_rgid
== target
->p_svgid
&&
494 (targetp
->p_traceflag
& KTRFAC_ROOT
) == 0) ||
495 caller
->pc_ucred
->cr_uid
== 0)