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