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