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.2 (Berkeley) 04/26/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 "../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 (!ktrace_nocheck && (u.u_error = suser(u.u_cred, &u.u_acflag))) 159 return; 160 if (ops != KTROP_CLEAR) { 161 /* 162 * an operation which requires a file argument. 163 */ 164 ndp->ni_nameiop = LOOKUP | FOLLOW; 165 ndp->ni_segflg = UIO_USERSPACE; 166 ndp->ni_dirp = uap->fname; 167 ip = namei(ndp); 168 if (ip == NULL) 169 return; 170 if ((ip->i_mode&IFMT) != IFREG) { 171 u.u_error = EACCES; 172 iput(ip); 173 return; 174 } 175 if (ip->i_fs->fs_ronly) { 176 u.u_error = EROFS; 177 iput(ip); 178 return; 179 } 180 iunlock(ip); 181 } 182 /* 183 * Clear all uses of the tracefile 184 */ 185 if (ops == KTROP_CLEARFILE) { 186 for (p = allproc; p != NULL; p = p->p_nxt) { 187 if (p->p_tracep == ip) { 188 p->p_flag &= ~SKTR; 189 p->p_tracep = NULL; 190 p->p_traceflag = 0; 191 irele(ip); 192 } 193 } 194 goto done; 195 } 196 197 /* 198 * need something to (un)trace 199 */ 200 if (!facs) { 201 u.u_error = EINVAL; 202 goto done; 203 } 204 205 if (uap->pid < 0) { 206 pg = pgfind(-uap->pid); 207 if (pg == NULL) { 208 u.u_error = ESRCH; 209 goto done; 210 } 211 for (p = pg->pg_mem; p != NULL; p = p->p_pgrpnxt) 212 if (uap->ops&KTROP_INHERITFLAG) 213 ktrsetchildren(p, ops, facs, ip); 214 else 215 ktrops(p, ops, facs, ip); 216 217 } else { 218 p = pfind(uap->pid); 219 if (p == NULL) { 220 u.u_error = ESRCH; 221 goto done; 222 } 223 if (uap->ops&KTROP_INHERITFLAG) 224 ktrsetchildren(p, ops, facs, ip); 225 else 226 ktrops(p, ops, facs, ip); 227 } 228 done: 229 if (ip != NULL) 230 irele(ip); 231 } 232 233 ktrops(p, ops, facs, ip) 234 struct proc *p; 235 struct inode *ip; 236 { 237 if (ops == KTROP_SET) { 238 if (p->p_tracep != ip) { 239 /* 240 * if trace file already in use, relinquish 241 */ 242 if (p->p_tracep != NULL) 243 irele(p->p_tracep); 244 igrab(ip); 245 p->p_tracep = ip; 246 iunlock(ip); 247 } 248 p->p_traceflag |= facs; 249 } else { 250 /* KTROP_CLEAR */ 251 if ((p->p_traceflag &= ~facs) == 0) { 252 if (p->p_tracep != NULL) { 253 irele(p->p_tracep); 254 p->p_tracep = NULL; 255 } 256 p->p_flag &= SKTR; 257 } 258 } 259 } 260 261 ktrsetchildren(top, ops, facs, ip) 262 struct proc *top; 263 struct inode *ip; 264 { 265 register struct proc *p; 266 register int ndx; 267 268 p = top; 269 for (;;) { 270 if (ops == KTROP_SET) 271 p->p_flag |= SKTR; 272 ktrops(p, ops, facs, ip); 273 /* 274 * If this process has children, descend to them next, 275 * otherwise do any siblings, and if done with this level, 276 * follow back up the tree (but not past top). 277 */ 278 if (p->p_cptr) 279 p = p->p_cptr; 280 else if (p == top) 281 return; 282 else if (p->p_osptr) 283 p = p->p_osptr; 284 else for (;;) { 285 p = p->p_pptr; 286 if (p == top) 287 return; 288 if (p->p_osptr) { 289 p = p->p_osptr; 290 break; 291 } 292 } 293 } 294 } 295 296 ktrwrite(ip, kth) 297 register struct inode *ip; 298 struct ktr_header *kth; 299 { 300 int save = u.u_error; 301 int osize; 302 303 ilock(ip); 304 osize = ip->i_size; 305 u.u_error = 0; 306 u.u_error = rdwri(UIO_WRITE, ip, (caddr_t)kth, 307 sizeof(struct ktr_header), ip->i_size, 1, (int *)0); 308 if (u.u_error) { 309 itrunc(ip, (u_long)osize); 310 goto end; 311 } 312 if (kth->ktr_len > 0) { 313 u.u_error = rdwri(UIO_WRITE, ip, kth->ktr_buf, 314 kth->ktr_len, ip->i_size, 1, (int *)0); 315 if (u.u_error) 316 itrunc(ip, (u_long)osize); 317 } 318 end: 319 u.u_error = save; 320 iunlock(ip); 321 } 322 323 #endif 324