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 are permitted 6 * provided that the above copyright notice and this paragraph are 7 * duplicated in all such forms and that any documentation, 8 * advertising materials, and other materials related to such 9 * distribution and use acknowledge that the software was developed 10 * by the University of California, Berkeley. The name of the 11 * University may not be used to endorse or promote products derived 12 * from this software without specific prior written permission. 13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 16 * 17 * @(#)kern_ktrace.c 1.3 (Berkeley) 05/01/89 18 */ 19 20 #ifdef KTRACE 21 22 #include "param.h" 23 #include "systm.h" 24 #include "dir.h" 25 #include "user.h" 26 #include "assym.s" 27 #include "proc.h" 28 #include "seg.h" 29 #include "acct.h" 30 #include "fs.h" 31 #include "inode.h" 32 #include "syslog.h" 33 #include "kernel.h" 34 #include "ktrace.h" 35 #include "malloc.h" 36 37 #include "syscalls.c" 38 39 extern int nsysent; 40 extern char *syscallnames[]; 41 42 int ktrace_nocheck = 1; 43 44 struct ktr_header * 45 ktrgetheader(type) 46 { 47 register struct ktr_header *kth; 48 49 MALLOC(kth, struct ktr_header *, sizeof (struct ktr_header), 50 M_TEMP, M_WAITOK); 51 if (kth == NULL) 52 return (NULL); 53 kth->ktr_type = type; 54 microtime(&kth->ktr_time); 55 kth->ktr_pid = u.u_procp->p_pid; 56 bcopy(u.u_comm, kth->ktr_comm, MAXCOMLEN); 57 58 if (kth == NULL) 59 printf("ktrgetheader: can't malloc header for %d\n", type); 60 return (kth); 61 } 62 63 ktrsyscall(ip, code, narg) 64 struct inode *ip; 65 { 66 struct ktr_header *kth = ktrgetheader(KTR_SYSCALL); 67 struct ktr_syscall *ktp; 68 register len = sizeof(struct ktr_syscall) + (narg * sizeof(int)); 69 int *argp, i; 70 71 if (kth == NULL) 72 return; 73 MALLOC(ktp, struct ktr_syscall *, len, M_TEMP, M_WAITOK); 74 if (ktp == NULL) { 75 printf("lost syscall trace - no buffer\n"); /* DEBUG */ 76 FREE(kth, M_TEMP); 77 return; 78 } 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++ = u.u_arg[i]; 84 kth->ktr_buf = (caddr_t)ktp; 85 kth->ktr_len = len; 86 ktrwrite(ip, kth); 87 FREE(ktp, M_TEMP); 88 FREE(kth, M_TEMP); 89 } 90 91 ktrsysret(ip, code) 92 struct inode *ip; 93 { 94 struct ktr_header *kth = ktrgetheader(KTR_SYSRET); 95 struct ktr_sysret *ktp; 96 97 if (kth == NULL) 98 return; 99 MALLOC(ktp, struct ktr_sysret *, sizeof(struct ktr_sysret), 100 M_TEMP , M_WAITOK); 101 if (ktp == NULL) { 102 printf("lost syscall ret - no buffer\n"); /* DEBUG */ 103 FREE(kth, M_TEMP); 104 return; 105 } 106 ktp->ktr_code = code; 107 ktp->ktr_eosys = u.u_eosys; 108 ktp->ktr_error = u.u_error; 109 ktp->ktr_retval = u.u_r.r_val1; /* what about val2 ? */ 110 111 kth->ktr_buf = (caddr_t)ktp; 112 kth->ktr_len = sizeof(struct ktr_sysret); 113 114 ktrwrite(ip, kth); 115 FREE(ktp, M_TEMP); 116 FREE(kth, M_TEMP); 117 } 118 119 ktrnamei(ip, path) 120 struct inode *ip; 121 char *path; 122 { 123 struct ktr_header *kth = ktrgetheader(KTR_NAMEI); 124 125 if (kth == NULL) 126 return; 127 kth->ktr_len = strlen(path); 128 kth->ktr_buf = path; 129 130 ktrwrite(ip, kth); 131 FREE(kth, M_TEMP); 132 } 133 134 ktrgenio(ip, fd, rw, iov, len) 135 struct inode *ip; 136 enum uio_rw rw; 137 register struct iovec *iov; 138 { 139 struct ktr_header *kth = ktrgetheader(KTR_GENIO); 140 register struct ktr_genio *ktp; 141 register caddr_t cp; 142 register int resid = len, cnt; 143 144 if (kth == NULL || u.u_error) 145 return; 146 MALLOC(ktp, struct ktr_genio *, sizeof(struct ktr_genio) + len, 147 M_TEMP, M_WAITOK); 148 if (ktp == NULL) { 149 printf("lost ktr_genio data buffer\n"); 150 FREE(kth, M_TEMP); 151 return; 152 } 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, 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(ip, kth); 169 done: 170 FREE(kth, M_TEMP); 171 FREE(ktp, M_TEMP); 172 } 173 174 /* 175 * ktrace system call 176 */ 177 ktrace() 178 { 179 register struct inode *ip = NULL; 180 register struct a { 181 char *fname; 182 int ops; 183 int facs; 184 int pid; 185 } *uap = (struct a *)u.u_ap; 186 register struct nameidata *ndp = &u.u_nd; 187 register struct proc *p; 188 struct pgrp *pg; 189 register int ops = uap->ops&0x3; 190 register int facs = uap->facs; 191 register int ret = 0; 192 193 /* 194 * Until security implications are thought through, 195 * limit tracing to root (unless ktrace_nocheck is set). 196 */ 197 if (!ktrace_nocheck && (u.u_error = suser(u.u_cred, &u.u_acflag))) 198 return; 199 if (ops != KTROP_CLEAR) { 200 /* 201 * an operation which requires a file argument. 202 */ 203 ndp->ni_nameiop = LOOKUP | FOLLOW; 204 ndp->ni_segflg = UIO_USERSPACE; 205 ndp->ni_dirp = uap->fname; 206 ip = namei(ndp); 207 if (ip == NULL) 208 return; 209 if (access(ip, IWRITE)) { 210 iput(ip); 211 return; 212 } 213 if ((ip->i_mode&IFMT) != IFREG) { 214 u.u_error = EACCES; 215 iput(ip); 216 return; 217 } 218 if (ip->i_fs->fs_ronly) { 219 u.u_error = EROFS; 220 iput(ip); 221 return; 222 } 223 iunlock(ip); 224 } 225 /* 226 * Clear all uses of the tracefile 227 */ 228 if (ops == KTROP_CLEARFILE) { 229 for (p = allproc; p != NULL; p = p->p_nxt) { 230 if (p->p_tracep == ip) { 231 p->p_flag &= ~SKTR; 232 p->p_tracep = NULL; 233 p->p_traceflag = 0; 234 irele(ip); 235 } 236 } 237 goto done; 238 } 239 240 /* 241 * need something to (un)trace 242 */ 243 if (!facs) { 244 u.u_error = EINVAL; 245 goto done; 246 } 247 248 if (uap->pid < 0) { 249 pg = pgfind(-uap->pid); 250 if (pg == NULL) { 251 u.u_error = ESRCH; 252 goto done; 253 } 254 for (p = pg->pg_mem; p != NULL; p = p->p_pgrpnxt) 255 if (uap->ops&KTROP_INHERITFLAG) 256 ret |= ktrsetchildren(p, ops, facs, ip); 257 else 258 ret |= ktrops(p, ops, facs, ip); 259 260 } else { 261 p = pfind(uap->pid); 262 if (p == NULL) { 263 u.u_error = ESRCH; 264 goto done; 265 } 266 if (uap->ops&KTROP_INHERITFLAG) 267 ret |= ktrsetchildren(p, ops, facs, ip); 268 else 269 ret |= ktrops(p, ops, facs, ip); 270 } 271 if (!ret) 272 u.u_error = EPERM; 273 done: 274 if (ip != NULL) 275 irele(ip); 276 } 277 278 ktrops(p, ops, facs, ip) 279 struct proc *p; 280 struct inode *ip; 281 { 282 283 if (u.u_uid && u.u_uid != p->p_uid) 284 return 0; 285 if (ops == KTROP_SET) { 286 if (p->p_tracep != ip) { 287 /* 288 * if trace file already in use, relinquish 289 */ 290 if (p->p_tracep != NULL) 291 irele(p->p_tracep); 292 igrab(ip); 293 p->p_tracep = ip; 294 iunlock(ip); 295 } 296 p->p_traceflag |= facs; 297 } else { 298 /* KTROP_CLEAR */ 299 if ((p->p_traceflag &= ~facs) == 0) { 300 if (p->p_tracep != NULL) { 301 irele(p->p_tracep); 302 p->p_tracep = NULL; 303 } 304 p->p_flag &= ~SKTR; 305 } 306 } 307 308 return 1; 309 } 310 311 ktrsetchildren(top, ops, facs, ip) 312 struct proc *top; 313 struct inode *ip; 314 { 315 register struct proc *p; 316 register int ndx; 317 register int ret = 0; 318 319 p = top; 320 for (;;) { 321 if ((ret |= ktrops(p, ops, facs, ip)) && ops == KTROP_SET) 322 p->p_flag |= SKTR; 323 /* 324 * If this process has children, descend to them next, 325 * otherwise do any siblings, and if done with this level, 326 * follow back up the tree (but not past top). 327 */ 328 if (p->p_cptr) 329 p = p->p_cptr; 330 else if (p == top) 331 return ret; 332 else if (p->p_osptr) 333 p = p->p_osptr; 334 else for (;;) { 335 p = p->p_pptr; 336 if (p == top) 337 return ret; 338 if (p->p_osptr) { 339 p = p->p_osptr; 340 break; 341 } 342 } 343 } 344 /*NOTREACHED*/ 345 } 346 347 ktrwrite(ip, kth) 348 register struct inode *ip; 349 struct ktr_header *kth; 350 { 351 int save = u.u_error; 352 int osize; 353 354 if (ip == NULL) 355 return; 356 ilock(ip); 357 osize = ip->i_size; 358 u.u_error = 0; 359 u.u_error = rdwri(UIO_WRITE, ip, (caddr_t)kth, 360 sizeof(struct ktr_header), ip->i_size, 1, (int *)0); 361 if (u.u_error) { 362 itrunc(ip, (u_long)osize); 363 goto end; 364 } 365 if (kth->ktr_len > 0) { 366 u.u_error = rdwri(UIO_WRITE, ip, kth->ktr_buf, 367 kth->ktr_len, ip->i_size, 1, (int *)0); 368 if (u.u_error) 369 itrunc(ip, (u_long)osize); 370 } 371 end: 372 u.u_error = save; 373 iunlock(ip); 374 } 375 376 #endif 377