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