darwin-xnu/bsd/kern/kern_ktrace.c
<<
>>
Prefs
   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
  79static struct ktr_header *ktrgetheader(int type);
  80static void ktrwrite(struct vnode *, struct ktr_header *, struct uio *);
  81static int ktrcanset(struct proc *,struct proc *);
  82static int ktrsetchildren(struct proc *,struct proc *,
  83        int, int, struct vnode *);
  84static int ktrops(struct proc *,struct proc *,int,int,struct vnode *);
  85
  86
  87static struct ktr_header *
  88ktrgetheader(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
 106void
 107ktrsyscall(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 
 153void
 154ktrsysret(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
 190void
 191ktrnamei(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
 212void
 213ktrgenio(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
 245void
 246ktrpsig(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
 275void
 276ktrcsw(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 */
 307int
 308ktrace(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;
 414done:
 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 */
 431int
 432utrace(__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
 470static int
 471ktrops(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
 512static int
 513ktrsetchildren(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
 544static void
 545ktrwrite(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 */
 599static int
 600ktrcanset(__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 */
 623
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.