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