]> git.saurik.com Git - apple/xnu.git/blob - bsd/kern/kern_ktrace.c
xnu-792.21.3.tar.gz
[apple/xnu.git] / bsd / kern / kern_ktrace.c
1 /*
2 * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28 /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
29 /*
30 * Copyright (c) 1989, 1993
31 * The Regents of the University of California. All rights reserved.
32 *
33 * Redistribution and use in source and binary forms, with or without
34 * modification, are permitted provided that the following conditions
35 * are met:
36 * 1. Redistributions of source code must retain the above copyright
37 * notice, this list of conditions and the following disclaimer.
38 * 2. Redistributions in binary form must reproduce the above copyright
39 * notice, this list of conditions and the following disclaimer in the
40 * documentation and/or other materials provided with the distribution.
41 * 3. All advertising materials mentioning features or use of this software
42 * must display the following acknowledgement:
43 * This product includes software developed by the University of
44 * California, Berkeley and its contributors.
45 * 4. Neither the name of the University nor the names of its contributors
46 * may be used to endorse or promote products derived from this software
47 * without specific prior written permission.
48 *
49 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
50 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
51 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
52 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
53 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
54 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
55 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
56 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
57 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
58 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
59 * SUCH DAMAGE.
60 *
61 * @(#)kern_ktrace.c 8.2 (Berkeley) 9/23/93
62 * $FreeBSD: src/sys/kern/kern_ktrace.c,v 1.35.2.4 2001/03/05 13:09:01 obrien Exp $
63 */
64
65
66 #include <sys/param.h>
67 #include <sys/systm.h>
68 #include <sys/types.h>
69 #include <sys/proc_internal.h>
70 #include <sys/kauth.h>
71 #include <sys/file_internal.h>
72 #include <sys/namei.h>
73 #include <sys/vnode_internal.h>
74 #if KTRACE
75 #include <sys/ktrace.h>
76 #endif
77 #include <sys/malloc.h>
78 #include <sys/syslog.h>
79 #include <sys/sysproto.h>
80 #include <sys/uio_internal.h>
81
82 #include <bsm/audit_kernel.h>
83
84 #if KTRACE
85 static struct ktr_header *ktrgetheader(int type);
86 static void ktrwrite(struct vnode *, struct ktr_header *, struct uio *);
87 static int ktrcanset(struct proc *,struct proc *);
88 static int ktrsetchildren(struct proc *,struct proc *,
89 int, int, struct vnode *);
90 static int ktrops(struct proc *,struct proc *,int,int,struct vnode *);
91
92
93 static struct ktr_header *
94 ktrgetheader(type)
95 int type;
96 {
97 register struct ktr_header *kth;
98 struct proc *p = current_proc(); /* XXX */
99
100 MALLOC(kth, struct ktr_header *, sizeof (struct ktr_header),
101 M_KTRACE, M_WAITOK);
102 if (kth != NULL) {
103 kth->ktr_type = type;
104 microtime(&kth->ktr_time);
105 kth->ktr_pid = p->p_pid;
106 bcopy(p->p_comm, kth->ktr_comm, MAXCOMLEN);
107 }
108 return (kth);
109 }
110 #endif
111
112 void
113 ktrsyscall(p, code, narg, args)
114 struct proc *p;
115 int code, narg;
116 u_int64_t args[];
117 {
118 #if KTRACE
119 struct vnode *vp;
120 struct ktr_header *kth;
121 struct ktr_syscall *ktp;
122 register int len;
123 u_int64_t *argp;
124 int i;
125
126 if (!KTRPOINT(p, KTR_SYSCALL))
127 return;
128
129 vp = p->p_tracep;
130 len = __offsetof(struct ktr_syscall, ktr_args) +
131 (narg * sizeof(u_int64_t));
132 p->p_traceflag |= KTRFAC_ACTIVE;
133 kth = ktrgetheader(KTR_SYSCALL);
134 if (kth == NULL) {
135 p->p_traceflag &= ~KTRFAC_ACTIVE;
136 return;
137 }
138 MALLOC(ktp, struct ktr_syscall *, len, M_KTRACE, M_WAITOK);
139 if (ktp == NULL) {
140 FREE(kth, M_KTRACE);
141 return;
142 }
143 ktp->ktr_code = code;
144 ktp->ktr_narg = narg;
145 argp = &ktp->ktr_args[0];
146 for (i = 0; i < narg; i++)
147 *argp++ = args[i];
148 kth->ktr_buf = (caddr_t)ktp;
149 kth->ktr_len = len;
150 ktrwrite(vp, kth, NULL);
151 FREE(ktp, M_KTRACE);
152 FREE(kth, M_KTRACE);
153 p->p_traceflag &= ~KTRFAC_ACTIVE;
154 #else
155 return;
156 #endif
157 }
158
159 void
160 ktrsysret(p, code, error, retval)
161 struct proc *p;
162 int code, error;
163 register_t retval;
164 {
165 #if KTRACE
166 struct vnode *vp;
167 struct ktr_header *kth;
168 struct ktr_sysret ktp;
169
170 if (!KTRPOINT(p, KTR_SYSRET))
171 return;
172
173 vp = p->p_tracep;
174 p->p_traceflag |= KTRFAC_ACTIVE;
175 kth = ktrgetheader(KTR_SYSRET);
176 if (kth == NULL) {
177 p->p_traceflag &= ~KTRFAC_ACTIVE;
178 return;
179 }
180 ktp.ktr_code = code;
181 ktp.ktr_error = error;
182 ktp.ktr_retval = retval; /* what about val2 ? */
183
184 kth->ktr_buf = (caddr_t)&ktp;
185 kth->ktr_len = sizeof(struct ktr_sysret);
186
187 ktrwrite(vp, kth, NULL);
188 FREE(kth, M_KTRACE);
189 p->p_traceflag &= ~KTRFAC_ACTIVE;
190 #else
191 return;
192 #endif
193 }
194
195 #if KTRACE
196 void
197 ktrnamei(vp, path)
198 struct vnode *vp;
199 char *path;
200 {
201 struct ktr_header *kth;
202 struct proc *p = current_proc(); /* XXX */
203
204 p->p_traceflag |= KTRFAC_ACTIVE;
205 kth = ktrgetheader(KTR_NAMEI);
206 if (kth == NULL) {
207 p->p_traceflag &= ~KTRFAC_ACTIVE;
208 return;
209 }
210 kth->ktr_len = strlen(path);
211 kth->ktr_buf = path;
212
213 ktrwrite(vp, kth, NULL);
214 FREE(kth, M_KTRACE);
215 p->p_traceflag &= ~KTRFAC_ACTIVE;
216 }
217
218 void
219 ktrgenio(vp, fd, rw, uio, error)
220 struct vnode *vp;
221 int fd;
222 enum uio_rw rw;
223 struct uio *uio;
224 int error;
225 {
226 struct ktr_header *kth;
227 struct ktr_genio ktg;
228 struct proc *p = current_proc(); /* XXX */
229
230 if (error)
231 return;
232
233 p->p_traceflag |= KTRFAC_ACTIVE;
234 kth = ktrgetheader(KTR_GENIO);
235 if (kth == NULL) {
236 p->p_traceflag &= ~KTRFAC_ACTIVE;
237 return;
238 }
239 ktg.ktr_fd = fd;
240 ktg.ktr_rw = rw;
241 kth->ktr_buf = (caddr_t)&ktg;
242 kth->ktr_len = sizeof(struct ktr_genio);
243 uio->uio_offset = 0;
244 uio->uio_rw = UIO_WRITE;
245
246 ktrwrite(vp, kth, uio);
247 FREE(kth, M_KTRACE);
248 p->p_traceflag &= ~KTRFAC_ACTIVE;
249 }
250
251 void
252 ktrpsig(vp, sig, action, mask, code)
253 struct vnode *vp;
254 int sig;
255 sig_t action;
256 sigset_t *mask;
257 int code;
258 {
259 struct ktr_header *kth;
260 struct ktr_psig kp;
261 struct proc *p = current_proc(); /* XXX */
262
263 p->p_traceflag |= KTRFAC_ACTIVE;
264 kth = ktrgetheader(KTR_PSIG);
265 if (kth == NULL) {
266 p->p_traceflag &= ~KTRFAC_ACTIVE;
267 return;
268 }
269 kp.signo = (char)sig;
270 kp.action = action;
271 kp.mask = *mask;
272 kp.code = code;
273 kth->ktr_buf = (caddr_t)&kp;
274 kth->ktr_len = sizeof (struct ktr_psig);
275
276 ktrwrite(vp, kth, NULL);
277 FREE(kth, M_KTRACE);
278 p->p_traceflag &= ~KTRFAC_ACTIVE;
279 }
280
281 void
282 ktrcsw(vp, out, user)
283 struct vnode *vp;
284 int out, user;
285 {
286 struct ktr_header *kth;
287 struct ktr_csw kc;
288 struct proc *p = current_proc(); /* XXX */
289
290 p->p_traceflag |= KTRFAC_ACTIVE;
291 kth = ktrgetheader(KTR_CSW);
292 if (kth == NULL) {
293 p->p_traceflag &= ~KTRFAC_ACTIVE;
294 return;
295 }
296 kc.out = out;
297 kc.user = user;
298 kth->ktr_buf = (caddr_t)&kc;
299 kth->ktr_len = sizeof (struct ktr_csw);
300
301 ktrwrite(vp, kth, NULL);
302 FREE(kth, M_KTRACE);
303 p->p_traceflag &= ~KTRFAC_ACTIVE;
304 }
305 #endif /* KTRACE */
306
307 /* Interface and common routines */
308
309 /*
310 * ktrace system call
311 */
312 /* ARGSUSED */
313 int
314 ktrace(struct proc *curp, register struct ktrace_args *uap, __unused register_t *retval)
315 {
316 #if KTRACE
317 register struct vnode *vp = NULL;
318 register struct proc *p;
319 struct pgrp *pg;
320 int facs = uap->facs & ~KTRFAC_ROOT;
321 int ops = KTROP(uap->ops);
322 int descend = uap->ops & KTRFLAG_DESCEND;
323 int ret = 0;
324 int error = 0;
325 struct nameidata nd;
326 struct vfs_context context;
327
328 AUDIT_ARG(cmd, uap->ops);
329 AUDIT_ARG(pid, uap->pid);
330 AUDIT_ARG(value, uap->facs);
331
332 context.vc_proc = curp;
333 context.vc_ucred = kauth_cred_get();
334
335 curp->p_traceflag |= KTRFAC_ACTIVE;
336 if (ops != KTROP_CLEAR) {
337 /*
338 * an operation which requires a file argument.
339 */
340 NDINIT(&nd, LOOKUP, (NOFOLLOW|LOCKLEAF), UIO_USERSPACE,
341 uap->fname, &context);
342 error = vn_open(&nd, FREAD|FWRITE|O_NOFOLLOW, 0);
343 if (error) {
344 curp->p_traceflag &= ~KTRFAC_ACTIVE;
345 return (error);
346 }
347 vp = nd.ni_vp;
348
349 if (vp->v_type != VREG) {
350 (void) vn_close(vp, FREAD|FWRITE, kauth_cred_get(), curp);
351 (void) vnode_put(vp);
352
353 curp->p_traceflag &= ~KTRFAC_ACTIVE;
354 return (EACCES);
355 }
356 }
357 /*
358 * Clear all uses of the tracefile
359 */
360 if (ops == KTROP_CLEARFILE) {
361 LIST_FOREACH(p, &allproc, p_list) {
362 if (p->p_tracep == vp) {
363 if (ktrcanset(curp, p)) {
364 struct vnode *tvp = p->p_tracep;
365 /* no more tracing */
366 p->p_traceflag = 0;
367 if (tvp != NULL) {
368 p->p_tracep = NULL;
369 vnode_rele(tvp);
370 }
371 } else
372 error = EPERM;
373 }
374 }
375 goto done;
376 }
377
378 /*
379 * need something to (un)trace (XXX - why is this here?)
380 */
381 if (!facs) {
382 error = EINVAL;
383 goto done;
384 }
385 /*
386 * do it
387 */
388 if (uap->pid < 0) {
389 /*
390 * by process group
391 */
392 pg = pgfind(-uap->pid);
393 if (pg == NULL) {
394 error = ESRCH;
395 goto done;
396 }
397 LIST_FOREACH(p, &pg->pg_members, p_pglist)
398 if (descend)
399 ret |= ktrsetchildren(curp, p, ops, facs, vp);
400 else
401 ret |= ktrops(curp, p, ops, facs, vp);
402
403 } else {
404 /*
405 * by pid
406 */
407 p = pfind(uap->pid);
408 if (p == NULL) {
409 error = ESRCH;
410 goto done;
411 }
412 AUDIT_ARG(process, p);
413 if (descend)
414 ret |= ktrsetchildren(curp, p, ops, facs, vp);
415 else
416 ret |= ktrops(curp, p, ops, facs, vp);
417 }
418 if (!ret)
419 error = EPERM;
420 done:
421 if (vp != NULL) {
422 (void) vn_close(vp, FWRITE, kauth_cred_get(), curp);
423 (void) vnode_put(vp);
424 }
425 curp->p_traceflag &= ~KTRFAC_ACTIVE;
426 return (error);
427 #else
428 return ENOSYS;
429 #endif
430 }
431
432 /*
433 * utrace system call
434 */
435
436 /* ARGSUSED */
437 int
438 utrace(__unused struct proc *curp, register struct utrace_args *uap, __unused register_t *retval)
439 {
440 #if KTRACE
441 struct ktr_header *kth;
442 struct proc *p = current_proc(); /* XXX */
443 register caddr_t cp;
444
445 if (!KTRPOINT(p, KTR_USER))
446 return (0);
447 if (uap->len > KTR_USER_MAXLEN)
448 return (EINVAL);
449 p->p_traceflag |= KTRFAC_ACTIVE;
450 kth = ktrgetheader(KTR_USER);
451 if (kth == NULL) {
452 p->p_traceflag &= ~KTRFAC_ACTIVE;
453 return(ENOMEM);
454 }
455 MALLOC(cp, caddr_t, uap->len, M_KTRACE, M_WAITOK);
456 if (cp == NULL) {
457 FREE(kth, M_KTRACE);
458 return(ENOMEM);
459 }
460 if (copyin(uap->addr, cp, uap->len) == 0) {
461 kth->ktr_buf = cp;
462 kth->ktr_len = uap->len;
463 ktrwrite(p->p_tracep, kth, NULL);
464 }
465 FREE(kth, M_KTRACE);
466 FREE(cp, M_KTRACE);
467 p->p_traceflag &= ~KTRFAC_ACTIVE;
468
469 return (0);
470 #else
471 return (ENOSYS);
472 #endif
473 }
474
475 #if KTRACE
476 static int
477 ktrops(curp, p, ops, facs, vp)
478 struct proc *p, *curp;
479 int ops, facs;
480 struct vnode *vp;
481 {
482 struct vnode *tvp;
483
484 if (!ktrcanset(curp, p))
485 return (0);
486 if (ops == KTROP_SET) {
487 if (p->p_tracep != vp) {
488 tvp = p->p_tracep;
489 vnode_ref(vp);
490 p->p_tracep = vp;
491
492 if (tvp != NULL) {
493 /*
494 * if trace file already in use, relinquish
495 */
496 vnode_rele(tvp);
497 }
498 }
499 p->p_traceflag |= facs;
500 if (!suser(kauth_cred_get(), NULL))
501 p->p_traceflag |= KTRFAC_ROOT;
502 } else {
503 /* KTROP_CLEAR */
504 if (((p->p_traceflag &= ~facs) & KTRFAC_MASK) == 0) {
505 /* no more tracing */
506 tvp = p->p_tracep;
507 p->p_traceflag = 0;
508 if (tvp != NULL) {
509 p->p_tracep = NULL;
510 vnode_rele(tvp);
511 }
512 }
513 }
514
515 return (1);
516 }
517
518 static int
519 ktrsetchildren(curp, top, ops, facs, vp)
520 struct proc *curp, *top;
521 int ops, facs;
522 struct vnode *vp;
523 {
524 register struct proc *p;
525 register int ret = 0;
526
527 p = top;
528 for (;;) {
529 ret |= ktrops(curp, p, ops, facs, vp);
530 /*
531 * If this process has children, descend to them next,
532 * otherwise do any siblings, and if done with this level,
533 * follow back up the tree (but not past top).
534 */
535 if (!LIST_EMPTY(&p->p_children))
536 p = LIST_FIRST(&p->p_children);
537 else for (;;) {
538 if (p == top)
539 return (ret);
540 if (LIST_NEXT(p, p_sibling)) {
541 p = LIST_NEXT(p, p_sibling);
542 break;
543 }
544 p = p->p_pptr;
545 }
546 }
547 /*NOTREACHED*/
548 }
549
550 static void
551 ktrwrite(struct vnode *vp, struct ktr_header *kth, struct uio *uio)
552 {
553 uio_t auio;
554 register struct proc *p = current_proc(); /* XXX */
555 struct vfs_context context;
556 int error;
557 char uio_buf[ UIO_SIZEOF(2) ];
558
559 if (vp == NULL)
560 return;
561
562 auio = uio_createwithbuffer(2, 0, UIO_SYSSPACE, UIO_WRITE,
563 &uio_buf[0], sizeof(uio_buf));
564 uio_addiov(auio, CAST_USER_ADDR_T(kth), sizeof(struct ktr_header));
565 context.vc_proc = p;
566 context.vc_ucred = kauth_cred_get();
567
568 if (kth->ktr_len > 0) {
569 uio_addiov(auio, CAST_USER_ADDR_T(kth->ktr_buf), kth->ktr_len);
570 if (uio != NULL)
571 kth->ktr_len += uio_resid(uio);
572 }
573 if ((error = vnode_getwithref(vp)) == 0) {
574 error = VNOP_WRITE(vp, auio, IO_UNIT | IO_APPEND, &context);
575 if (error == 0 && uio != NULL) {
576 error = VNOP_WRITE(vp, uio, IO_UNIT | IO_APPEND, &context);
577 }
578 vnode_put(vp);
579 }
580 if (error) {
581 /*
582 * If error encountered, give up tracing on this vnode.
583 */
584 log(LOG_NOTICE, "ktrace write failed, errno %d, tracing stopped\n",
585 error);
586 LIST_FOREACH(p, &allproc, p_list) {
587 if (p->p_tracep == vp) {
588 p->p_tracep = NULL;
589 p->p_traceflag = 0;
590 vnode_rele(vp);
591 }
592 }
593 }
594 }
595
596 /*
597 * Return true if caller has permission to set the ktracing state
598 * of target. Essentially, the target can't possess any
599 * more permissions than the caller. KTRFAC_ROOT signifies that
600 * root previously set the tracing status on the target process, and
601 * so, only root may further change it.
602 *
603 * TODO: check groups. use caller effective gid.
604 */
605 static int
606 ktrcanset(__unused struct proc *callp, struct proc *targetp)
607 {
608 kauth_cred_t caller = kauth_cred_get();
609 kauth_cred_t target = targetp->p_ucred; /* XXX */
610
611 #if 0
612 /* PRISON_CHECK was defined to 1 always .... */
613 if (!PRISON_CHECK(callp, targetp))
614 return (0);
615 #endif
616 if ((kauth_cred_getuid(caller) == target->cr_ruid &&
617 target->cr_ruid == target->cr_svuid &&
618 caller->cr_rgid == target->cr_rgid && /* XXX */
619 target->cr_rgid == target->cr_svgid &&
620 (targetp->p_traceflag & KTRFAC_ROOT) == 0 &&
621 (targetp->p_flag & P_SUGID) == 0) ||
622 !suser(caller, NULL))
623 return (1);
624
625 return (0);
626 }
627
628 #endif /* KTRACE */