1 /* 2 * Copyright (c) 1989 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 * 7 * @(#)kern_ktrace.c 7.11 (Berkeley) 03/17/91 8 */ 9 10 #ifdef KTRACE 11 12 #include "param.h" 13 #include "namei.h" 14 #include "proc.h" 15 #include "file.h" 16 #include "vnode.h" 17 #include "ktrace.h" 18 #include "malloc.h" 19 #include "syslog.h" 20 #include "user.h" /* XXX for curproc */ 21 22 struct ktr_header * 23 ktrgetheader(type) 24 { 25 register struct ktr_header *kth; 26 struct proc *p = curproc; 27 28 MALLOC(kth, struct ktr_header *, sizeof (struct ktr_header), 29 M_TEMP, M_WAITOK); 30 kth->ktr_type = type; 31 microtime(&kth->ktr_time); 32 kth->ktr_pid = p->p_pid; 33 bcopy(p->p_comm, kth->ktr_comm, MAXCOMLEN); 34 return (kth); 35 } 36 37 ktrsyscall(vp, code, narg, args) 38 struct vnode *vp; 39 int code, narg, args[]; 40 { 41 struct ktr_header *kth = ktrgetheader(KTR_SYSCALL); 42 struct ktr_syscall *ktp; 43 register len = sizeof(struct ktr_syscall) + (narg * sizeof(int)); 44 int *argp, i; 45 46 MALLOC(ktp, struct ktr_syscall *, len, M_TEMP, M_WAITOK); 47 ktp->ktr_code = code; 48 ktp->ktr_narg = narg; 49 argp = (int *)((char *)ktp + sizeof(struct ktr_syscall)); 50 for (i = 0; i < narg; i++) 51 *argp++ = args[i]; 52 kth->ktr_buf = (caddr_t)ktp; 53 kth->ktr_len = len; 54 ktrwrite(vp, kth); 55 FREE(ktp, M_TEMP); 56 FREE(kth, M_TEMP); 57 } 58 59 ktrsysret(vp, code, error, retval) 60 struct vnode *vp; 61 int code, error, retval; 62 { 63 struct ktr_header *kth = ktrgetheader(KTR_SYSRET); 64 struct ktr_sysret ktp; 65 66 ktp.ktr_code = code; 67 ktp.ktr_error = error; 68 ktp.ktr_retval = retval; /* what about val2 ? */ 69 70 kth->ktr_buf = (caddr_t)&ktp; 71 kth->ktr_len = sizeof(struct ktr_sysret); 72 73 ktrwrite(vp, kth); 74 FREE(kth, M_TEMP); 75 } 76 77 ktrnamei(vp, path) 78 struct vnode *vp; 79 char *path; 80 { 81 struct ktr_header *kth = ktrgetheader(KTR_NAMEI); 82 83 kth->ktr_len = strlen(path); 84 kth->ktr_buf = path; 85 86 ktrwrite(vp, kth); 87 FREE(kth, M_TEMP); 88 } 89 90 ktrgenio(vp, fd, rw, iov, len, error) 91 struct vnode *vp; 92 int fd; 93 enum uio_rw rw; 94 register struct iovec *iov; 95 { 96 struct ktr_header *kth = ktrgetheader(KTR_GENIO); 97 register struct ktr_genio *ktp; 98 register caddr_t cp; 99 register int resid = len, cnt; 100 101 if (error) 102 return; 103 MALLOC(ktp, struct ktr_genio *, sizeof(struct ktr_genio) + len, 104 M_TEMP, M_WAITOK); 105 ktp->ktr_fd = fd; 106 ktp->ktr_rw = rw; 107 cp = (caddr_t)((char *)ktp + sizeof (struct ktr_genio)); 108 while (resid > 0) { 109 if ((cnt = iov->iov_len) > resid) 110 cnt = resid; 111 if (copyin(iov->iov_base, cp, (unsigned)cnt)) 112 goto done; 113 cp += cnt; 114 resid -= cnt; 115 iov++; 116 } 117 kth->ktr_buf = (caddr_t)ktp; 118 kth->ktr_len = sizeof (struct ktr_genio) + len; 119 120 ktrwrite(vp, kth); 121 done: 122 FREE(kth, M_TEMP); 123 FREE(ktp, M_TEMP); 124 } 125 126 ktrpsig(vp, sig, action, mask, code) 127 struct vnode *vp; 128 sig_t action; 129 { 130 struct ktr_header *kth = ktrgetheader(KTR_PSIG); 131 struct ktr_psig kp; 132 133 kp.signo = (char)sig; 134 kp.action = action; 135 kp.mask = mask; 136 kp.code = code; 137 kth->ktr_buf = (caddr_t)&kp; 138 kth->ktr_len = sizeof (struct ktr_psig); 139 140 ktrwrite(vp, kth); 141 FREE(kth, M_TEMP); 142 } 143 144 /* Interface and common routines */ 145 146 /* 147 * ktrace system call 148 */ 149 /* ARGSUSED */ 150 ktrace(curp, uap, retval) 151 struct proc *curp; 152 register struct args { 153 char *fname; 154 int ops; 155 int facs; 156 int pid; 157 } *uap; 158 int *retval; 159 { 160 register struct vnode *vp = NULL; 161 register struct proc *p; 162 struct pgrp *pg; 163 int facs = uap->facs & ~KTRFAC_ROOT; 164 int ops = KTROP(uap->ops); 165 int descend = uap->ops & KTRFLAG_DESCEND; 166 int ret = 0; 167 int error = 0; 168 struct nameidata nd; 169 170 if (ops != KTROP_CLEAR) { 171 /* 172 * an operation which requires a file argument. 173 */ 174 nd.ni_segflg = UIO_USERSPACE; 175 nd.ni_dirp = uap->fname; 176 if (error = vn_open(&nd, curp, FREAD|FWRITE, 0)) 177 return (error); 178 vp = nd.ni_vp; 179 if (vp->v_type != VREG) { 180 vrele(vp); 181 return (EACCES); 182 } 183 } 184 /* 185 * Clear all uses of the tracefile 186 */ 187 if (ops == KTROP_CLEARFILE) { 188 for (p = allproc; p != NULL; p = p->p_nxt) { 189 if (p->p_tracep == vp) { 190 if (ktrcanset(curp, p)) { 191 p->p_tracep = NULL; 192 p->p_traceflag = 0; 193 vrele(vp); 194 } else 195 error = EPERM; 196 } 197 } 198 goto done; 199 } 200 /* 201 * need something to (un)trace (XXX - why is this here?) 202 */ 203 if (!facs) { 204 error = EINVAL; 205 goto done; 206 } 207 /* 208 * do it 209 */ 210 if (uap->pid < 0) { 211 /* 212 * by process group 213 */ 214 pg = pgfind(-uap->pid); 215 if (pg == NULL) { 216 error = ESRCH; 217 goto done; 218 } 219 for (p = pg->pg_mem; p != NULL; p = p->p_pgrpnxt) 220 if (descend) 221 ret |= ktrsetchildren(curp, p, ops, facs, vp); 222 else 223 ret |= ktrops(curp, p, ops, facs, vp); 224 225 } else { 226 /* 227 * by pid 228 */ 229 p = pfind(uap->pid); 230 if (p == NULL) { 231 error = ESRCH; 232 goto done; 233 } 234 if (descend) 235 ret |= ktrsetchildren(curp, p, ops, facs, vp); 236 else 237 ret |= ktrops(curp, p, ops, facs, vp); 238 } 239 if (!ret) 240 error = EPERM; 241 done: 242 if (vp != NULL) 243 vrele(vp); 244 return (error); 245 } 246 247 ktrops(curp, p, ops, facs, vp) 248 struct proc *curp, *p; 249 struct vnode *vp; 250 { 251 252 if (!ktrcanset(curp, p)) 253 return (0); 254 if (ops == KTROP_SET) { 255 if (p->p_tracep != vp) { 256 /* 257 * if trace file already in use, relinquish 258 */ 259 if (p->p_tracep != NULL) 260 vrele(p->p_tracep); 261 VREF(vp); 262 p->p_tracep = vp; 263 } 264 p->p_traceflag |= facs; 265 if (curp->p_ucred->cr_uid == 0) 266 p->p_traceflag |= KTRFAC_ROOT; 267 } else { 268 /* KTROP_CLEAR */ 269 if (((p->p_traceflag &= ~facs) & KTRFAC_MASK) == 0) { 270 /* no more tracing */ 271 p->p_traceflag = 0; 272 if (p->p_tracep != NULL) { 273 vrele(p->p_tracep); 274 p->p_tracep = NULL; 275 } 276 } 277 } 278 279 return (1); 280 } 281 282 ktrsetchildren(curp, top, ops, facs, vp) 283 struct proc *curp, *top; 284 struct vnode *vp; 285 { 286 register struct proc *p; 287 register int ret = 0; 288 289 p = top; 290 for (;;) { 291 ret |= ktrops(curp, p, ops, facs, vp); 292 /* 293 * If this process has children, descend to them next, 294 * otherwise do any siblings, and if done with this level, 295 * follow back up the tree (but not past top). 296 */ 297 if (p->p_cptr) 298 p = p->p_cptr; 299 else if (p == top) 300 return (ret); 301 else if (p->p_osptr) 302 p = p->p_osptr; 303 else for (;;) { 304 p = p->p_pptr; 305 if (p == top) 306 return (ret); 307 if (p->p_osptr) { 308 p = p->p_osptr; 309 break; 310 } 311 } 312 } 313 /*NOTREACHED*/ 314 } 315 316 ktrwrite(vp, kth) 317 struct vnode *vp; 318 register struct ktr_header *kth; 319 { 320 struct uio auio; 321 struct iovec aiov[2]; 322 struct proc *p; 323 int error; 324 325 if (vp == NULL) 326 return; 327 auio.uio_iov = &aiov[0]; 328 auio.uio_offset = 0; 329 auio.uio_segflg = UIO_SYSSPACE; 330 auio.uio_rw = UIO_WRITE; 331 aiov[0].iov_base = (caddr_t)kth; 332 aiov[0].iov_len = sizeof(struct ktr_header); 333 auio.uio_resid = sizeof(struct ktr_header); 334 auio.uio_iovcnt = 1; 335 if (kth->ktr_len > 0) { 336 auio.uio_iovcnt++; 337 aiov[1].iov_base = kth->ktr_buf; 338 aiov[1].iov_len = kth->ktr_len; 339 auio.uio_resid += kth->ktr_len; 340 } 341 VOP_LOCK(vp); 342 error = VOP_WRITE(vp, &auio, IO_UNIT|IO_APPEND, curproc->p_ucred); 343 VOP_UNLOCK(vp); 344 if (!error) 345 return; 346 /* 347 * If error encountered, give up tracing on this vnode. 348 */ 349 log(LOG_NOTICE, "ktrace write failed, errno %d, tracing stopped\n", 350 error); 351 for (p = allproc; p != NULL; p = p->p_nxt) { 352 if (p->p_tracep == vp) { 353 p->p_tracep = NULL; 354 p->p_traceflag = 0; 355 vrele(vp); 356 } 357 } 358 } 359 360 /* 361 * Return true if caller has permission to set the ktracing state 362 * of target. Essentially, the target can't possess any 363 * more permissions than the caller. KTRFAC_ROOT signifies that 364 * root previously set the tracing status on the target process, and 365 * so, only root may further change it. 366 * 367 * TODO: check groups. use caller effective gid. 368 */ 369 ktrcanset(callp, targetp) 370 struct proc *callp, *targetp; 371 { 372 register struct pcred *caller = callp->p_cred; 373 register struct pcred *target = targetp->p_cred; 374 375 if ((caller->pc_ucred->cr_uid == target->p_ruid && 376 target->p_ruid == target->p_svuid && 377 caller->p_rgid == target->p_rgid && /* XXX */ 378 target->p_rgid == target->p_svgid && 379 (targetp->p_traceflag & KTRFAC_ROOT) == 0) || 380 caller->pc_ucred->cr_uid == 0) 381 return (1); 382 383 return (0); 384 } 385 386 #endif 387