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