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.1 (Berkeley) 12/14/88 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 "../sys/syscalls.c" 38 39 extern int nsysent; 40 extern char *syscallnames[]; 41 42 struct ktr_header * 43 ktrgetheader(type) 44 { 45 register struct ktr_header *kth; 46 47 MALLOC(kth, struct ktr_header *, sizeof (struct ktr_header), 48 M_TEMP, M_WAITOK); 49 if (kth == NULL) 50 return (NULL); 51 kth->ktr_type = type; 52 kth->ktr_time = time; 53 kth->ktr_pid = u.u_procp->p_pid; 54 bcopy(u.u_comm, kth->ktr_comm, MAXCOMLEN); 55 56 return (kth); 57 } 58 59 ktrsyscall(ip, code, narg) 60 struct inode *ip; 61 { 62 struct ktr_header *kth = ktrgetheader(KTR_SYSCALL); 63 struct ktr_syscall *ktp; 64 register len = sizeof(struct ktr_syscall) + (narg * sizeof(int)); 65 int *argp, i; 66 67 if (kth == NULL) { 68 printf("lost syscall trace - no header\n"); /* DEBUG */ 69 return; 70 } 71 MALLOC(ktp, struct ktr_syscall *, len, M_TEMP, M_WAITOK); 72 if (ktp == NULL) { 73 printf("lost syscall trace - no buffer\n"); /* DEBUG */ 74 FREE(kth, M_TEMP); 75 return; 76 } 77 ktp->ktr_code = code; 78 ktp->ktr_narg = narg; 79 argp = (int *)((char *)ktp + sizeof(struct ktr_syscall)); 80 for (i = 0; i < narg; i++) 81 *argp++ = u.u_arg[i]; 82 kth->ktr_buf = (caddr_t)ktp; 83 kth->ktr_len = len; 84 ktrwrite(ip, kth); 85 FREE(ktp, M_TEMP); 86 FREE(kth, M_TEMP); 87 } 88 89 ktrsysret(ip, code) 90 struct inode *ip; 91 { 92 struct ktr_header *kth = ktrgetheader(KTR_SYSRET); 93 struct ktr_sysret *ktp; 94 95 if (kth == NULL) { 96 printf("lost syscall ret - no header\n"); /* DEBUG */ 97 return; 98 } 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 printf("lost namei - no header\n"); /* DEBUG */ 127 return; 128 } 129 kth->ktr_len = strlen(path); 130 kth->ktr_buf = path; 131 132 ktrwrite(ip, kth); 133 FREE(kth, M_TEMP); 134 } 135 136 /* 137 * ktrace system call 138 */ 139 ktrace() 140 { 141 register struct inode *ip = NULL; 142 register struct a { 143 char *fname; 144 int ops; 145 int facs; 146 pid_t pid; 147 } *uap = (struct a *)u.u_ap; 148 register struct nameidata *ndp = &u.u_nd; 149 register struct proc *p; 150 struct pgrp *pg; 151 register int ops = uap->ops&0x3; 152 register int facs = uap->facs; 153 154 /* 155 * Until security implications are thought through, 156 * limit tracing to root. 157 */ 158 if (!suser()) { 159 u.u_error = EACCES; 160 return; 161 } 162 if (ops != KTROP_CLEAR) { 163 /* 164 * an operation which requires a file argument. 165 */ 166 ndp->ni_nameiop = LOOKUP | FOLLOW; 167 ndp->ni_segflg = UIO_USERSPACE; 168 ndp->ni_dirp = uap->fname; 169 ip = namei(ndp); 170 if (ip == NULL) 171 return; 172 if ((ip->i_mode&IFMT) != IFREG) { 173 u.u_error = EACCES; 174 iput(ip); 175 return; 176 } 177 if (ip->i_fs->fs_ronly) { 178 u.u_error = EROFS; 179 iput(ip); 180 return; 181 } 182 iunlock(ip); 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 == ip) { 190 p->p_flag &= ~SKTR; 191 p->p_tracep = NULL; 192 p->p_traceflag = 0; 193 irele(ip); 194 } 195 } 196 goto done; 197 } 198 199 /* 200 * need something to (un)trace 201 */ 202 if (!facs) { 203 u.u_error = EINVAL; 204 goto done; 205 } 206 207 if (uap->pid < 0) { 208 pg = pgfind(-uap->pid); 209 if (pg == NULL) { 210 u.u_error = ESRCH; 211 goto done; 212 } 213 for (p = pg->pg_mem; p != NULL; p = p->p_pgrpnxt) 214 if (uap->ops&KTROP_INHERITFLAG) 215 ktrsetchildren(p, ops, facs, ip); 216 else 217 ktrops(p, ops, facs, ip); 218 219 } else { 220 p = pfind(uap->pid); 221 if (p == NULL) { 222 u.u_error = ESRCH; 223 goto done; 224 } 225 if (uap->ops&KTROP_INHERITFLAG) 226 ktrsetchildren(p, ops, facs, ip); 227 else 228 ktrops(p, ops, facs, ip); 229 } 230 done: 231 if (ip != NULL) 232 irele(ip); 233 } 234 235 ktrops(p, ops, facs, ip) 236 struct proc *p; 237 struct inode *ip; 238 { 239 if (ops == KTROP_SET) { 240 if (p->p_tracep != ip) { 241 /* 242 * if trace file already in use, relinquish 243 */ 244 if (p->p_tracep != NULL) 245 irele(p->p_tracep); 246 igrab(ip); 247 p->p_tracep = ip; 248 iunlock(ip); 249 } 250 p->p_traceflag |= facs; 251 } else { 252 /* KTROP_CLEAR */ 253 if ((p->p_traceflag &= ~facs) == 0) { 254 if (p->p_tracep != NULL) { 255 irele(p->p_tracep); 256 p->p_tracep = NULL; 257 } 258 p->p_flag &= SKTR; 259 } 260 } 261 } 262 263 ktrsetchildren(top, ops, facs, ip) 264 struct proc *top; 265 struct inode *ip; 266 { 267 register struct proc *p; 268 register int ndx; 269 270 p = top; 271 for (;;) { 272 if (ops == KTROP_SET) 273 p->p_flag |= SKTR; 274 ktrops(p, ops, facs, ip); 275 /* 276 * If this process has children, descend to them next, 277 * otherwise do any siblings, and if done with this level, 278 * follow back up the tree (but not past top). 279 */ 280 if (p->p_cptr) 281 p = p->p_cptr; 282 else if (p == top) 283 return; 284 else if (p->p_osptr) 285 p = p->p_osptr; 286 else for (;;) { 287 p = p->p_pptr; 288 if (p == top) 289 return; 290 if (p->p_osptr) { 291 p = p->p_osptr; 292 break; 293 } 294 } 295 } 296 } 297 298 ktrwrite(ip, kth) 299 register struct inode *ip; 300 struct ktr_header *kth; 301 { 302 int save = u.u_error; 303 int osize; 304 305 ilock(ip); 306 osize = ip->i_size; 307 u.u_error = 0; 308 u.u_error = rdwri(UIO_WRITE, ip, (caddr_t)kth, 309 sizeof(struct ktr_header), ip->i_size, 1, (int *)0); 310 if (u.u_error) { 311 itrunc(ip, (u_long)osize); 312 goto end; 313 } 314 if (kth->ktr_len > 0) { 315 u.u_error = rdwri(UIO_WRITE, ip, kth->ktr_buf, 316 kth->ktr_len, ip->i_size, 1, (int *)0); 317 if (u.u_error) 318 itrunc(ip, (u_long)osize); 319 } 320 end: 321 u.u_error = save; 322 iunlock(ip); 323 } 324 325 #endif 326