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