1 /* $NetBSD: kern_ktrace.c,v 1.17 1995/03/26 07:48:47 cgd 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 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_TEMP, 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_TEMP); 180 FREE(ktp, M_TEMP); 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_TEMP); 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_TEMP); 227 p->p_traceflag &= ~KTRFAC_ACTIVE; 228 } 229 230 /* Interface and common routines */ 231 232 /* 233 * ktrace system call 234 */ 235 /* ARGSUSED */ 236 int 237 ktrace(curp, uap, retval) 238 struct proc *curp; 239 register struct ktrace_args /* { 240 syscallarg(char *) fname; 241 syscallarg(int) ops; 242 syscallarg(int) facs; 243 syscallarg(int) pid; 244 } */ *uap; 245 register_t *retval; 246 { 247 register struct vnode *vp = NULL; 248 register struct proc *p; 249 struct pgrp *pg; 250 int facs = SCARG(uap, facs) & ~KTRFAC_ROOT; 251 int ops = KTROP(SCARG(uap, ops)); 252 int descend = SCARG(uap, ops) & KTRFLAG_DESCEND; 253 int ret = 0; 254 int error = 0; 255 struct nameidata nd; 256 257 curp->p_traceflag |= KTRFAC_ACTIVE; 258 if (ops != KTROP_CLEAR) { 259 /* 260 * an operation which requires a file argument. 261 */ 262 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, fname), 263 curp); 264 if (error = vn_open(&nd, FREAD|FWRITE, 0)) { 265 curp->p_traceflag &= ~KTRFAC_ACTIVE; 266 return (error); 267 } 268 vp = nd.ni_vp; 269 VOP_UNLOCK(vp); 270 if (vp->v_type != VREG) { 271 (void) vn_close(vp, FREAD|FWRITE, curp->p_ucred, curp); 272 curp->p_traceflag &= ~KTRFAC_ACTIVE; 273 return (EACCES); 274 } 275 } 276 /* 277 * Clear all uses of the tracefile 278 */ 279 if (ops == KTROP_CLEARFILE) { 280 for (p = allproc.lh_first; p != 0; p = p->p_list.le_next) { 281 if (p->p_tracep == vp) { 282 if (ktrcanset(curp, p)) { 283 p->p_tracep = NULL; 284 p->p_traceflag = 0; 285 (void) vn_close(vp, FREAD|FWRITE, 286 p->p_ucred, p); 287 } else 288 error = EPERM; 289 } 290 } 291 goto done; 292 } 293 /* 294 * need something to (un)trace (XXX - why is this here?) 295 */ 296 if (!facs) { 297 error = EINVAL; 298 goto done; 299 } 300 /* 301 * do it 302 */ 303 if (SCARG(uap, pid) < 0) { 304 /* 305 * by process group 306 */ 307 pg = pgfind(-SCARG(uap, pid)); 308 if (pg == NULL) { 309 error = ESRCH; 310 goto done; 311 } 312 for (p = pg->pg_members.lh_first; p != 0; p = p->p_pglist.le_next) 313 if (descend) 314 ret |= ktrsetchildren(curp, p, ops, facs, vp); 315 else 316 ret |= ktrops(curp, p, ops, facs, vp); 317 318 } else { 319 /* 320 * by pid 321 */ 322 p = pfind(SCARG(uap, pid)); 323 if (p == NULL) { 324 error = ESRCH; 325 goto done; 326 } 327 if (descend) 328 ret |= ktrsetchildren(curp, p, ops, facs, vp); 329 else 330 ret |= ktrops(curp, p, ops, facs, vp); 331 } 332 if (!ret) 333 error = EPERM; 334 done: 335 if (vp != NULL) 336 (void) vn_close(vp, FWRITE, curp->p_ucred, curp); 337 curp->p_traceflag &= ~KTRFAC_ACTIVE; 338 return (error); 339 } 340 341 int 342 ktrops(curp, p, ops, facs, vp) 343 struct proc *p, *curp; 344 int ops, facs; 345 struct vnode *vp; 346 { 347 348 if (!ktrcanset(curp, p)) 349 return (0); 350 if (ops == KTROP_SET) { 351 if (p->p_tracep != vp) { 352 /* 353 * if trace file already in use, relinquish 354 */ 355 if (p->p_tracep != NULL) 356 vrele(p->p_tracep); 357 VREF(vp); 358 p->p_tracep = vp; 359 } 360 p->p_traceflag |= facs; 361 if (curp->p_ucred->cr_uid == 0) 362 p->p_traceflag |= KTRFAC_ROOT; 363 } else { 364 /* KTROP_CLEAR */ 365 if (((p->p_traceflag &= ~facs) & KTRFAC_MASK) == 0) { 366 /* no more tracing */ 367 p->p_traceflag = 0; 368 if (p->p_tracep != NULL) { 369 vrele(p->p_tracep); 370 p->p_tracep = NULL; 371 } 372 } 373 } 374 375 return (1); 376 } 377 378 ktrsetchildren(curp, top, ops, facs, vp) 379 struct proc *curp, *top; 380 int ops, facs; 381 struct vnode *vp; 382 { 383 register struct proc *p; 384 register int ret = 0; 385 386 p = top; 387 for (;;) { 388 ret |= ktrops(curp, p, ops, facs, vp); 389 /* 390 * If this process has children, descend to them next, 391 * otherwise do any siblings, and if done with this level, 392 * follow back up the tree (but not past top). 393 */ 394 if (p->p_children.lh_first) 395 p = p->p_children.lh_first; 396 else for (;;) { 397 if (p == top) 398 return (ret); 399 if (p->p_sibling.le_next) { 400 p = p->p_sibling.le_next; 401 break; 402 } 403 p = p->p_pptr; 404 } 405 } 406 /*NOTREACHED*/ 407 } 408 409 ktrwrite(vp, kth) 410 struct vnode *vp; 411 register struct ktr_header *kth; 412 { 413 struct uio auio; 414 struct iovec aiov[2]; 415 register struct proc *p = curproc; /* XXX */ 416 int error; 417 418 if (vp == NULL) 419 return; 420 auio.uio_iov = &aiov[0]; 421 auio.uio_offset = 0; 422 auio.uio_segflg = UIO_SYSSPACE; 423 auio.uio_rw = UIO_WRITE; 424 aiov[0].iov_base = (caddr_t)kth; 425 aiov[0].iov_len = sizeof(struct ktr_header); 426 auio.uio_resid = sizeof(struct ktr_header); 427 auio.uio_iovcnt = 1; 428 auio.uio_procp = (struct proc *)0; 429 if (kth->ktr_len > 0) { 430 auio.uio_iovcnt++; 431 aiov[1].iov_base = kth->ktr_buf; 432 aiov[1].iov_len = kth->ktr_len; 433 auio.uio_resid += kth->ktr_len; 434 } 435 VOP_LOCK(vp); 436 error = VOP_WRITE(vp, &auio, IO_UNIT|IO_APPEND, p->p_ucred); 437 VOP_UNLOCK(vp); 438 if (!error) 439 return; 440 /* 441 * If error encountered, give up tracing on this vnode. 442 */ 443 log(LOG_NOTICE, "ktrace write failed, errno %d, tracing stopped\n", 444 error); 445 for (p = allproc.lh_first; p != 0; p = p->p_list.le_next) { 446 if (p->p_tracep == vp) { 447 p->p_tracep = NULL; 448 p->p_traceflag = 0; 449 vrele(vp); 450 } 451 } 452 } 453 454 /* 455 * Return true if caller has permission to set the ktracing state 456 * of target. Essentially, the target can't possess any 457 * more permissions than the caller. KTRFAC_ROOT signifies that 458 * root previously set the tracing status on the target process, and 459 * so, only root may further change it. 460 * 461 * TODO: check groups. use caller effective gid. 462 */ 463 ktrcanset(callp, targetp) 464 struct proc *callp, *targetp; 465 { 466 register struct pcred *caller = callp->p_cred; 467 register struct pcred *target = targetp->p_cred; 468 469 if ((caller->pc_ucred->cr_uid == target->p_ruid && 470 target->p_ruid == target->p_svuid && 471 caller->p_rgid == target->p_rgid && /* XXX */ 472 target->p_rgid == target->p_svgid && 473 (targetp->p_traceflag & KTRFAC_ROOT) == 0) || 474 caller->pc_ucred->cr_uid == 0) 475 return (1); 476 477 return (0); 478 } 479 480 #endif 481