Commit | Line | Data |
---|---|---|
2d68027d MT |
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 | * | |
c4ec2128 | 17 | * @(#)kern_ktrace.c 1.4 (Berkeley) %G% |
2d68027d MT |
18 | */ |
19 | ||
20 | #ifdef KTRACE | |
21 | ||
22 | #include "param.h" | |
2d68027d | 23 | #include "user.h" |
2d68027d | 24 | #include "proc.h" |
c4ec2128 KM |
25 | #include "file.h" |
26 | #include "vnode.h" | |
2d68027d MT |
27 | #include "ktrace.h" |
28 | #include "malloc.h" | |
29 | ||
f73d8bd6 | 30 | #include "syscalls.c" |
2d68027d MT |
31 | |
32 | extern int nsysent; | |
33 | extern char *syscallnames[]; | |
34 | ||
f73d8bd6 MT |
35 | int ktrace_nocheck = 1; |
36 | ||
2d68027d MT |
37 | struct ktr_header * |
38 | ktrgetheader(type) | |
39 | { | |
40 | register struct ktr_header *kth; | |
41 | ||
42 | MALLOC(kth, struct ktr_header *, sizeof (struct ktr_header), | |
43 | M_TEMP, M_WAITOK); | |
2d68027d | 44 | kth->ktr_type = type; |
f73d8bd6 | 45 | microtime(&kth->ktr_time); |
2d68027d MT |
46 | kth->ktr_pid = u.u_procp->p_pid; |
47 | bcopy(u.u_comm, kth->ktr_comm, MAXCOMLEN); | |
2d68027d MT |
48 | return (kth); |
49 | } | |
50 | ||
c4ec2128 KM |
51 | ktrsyscall(vp, code, narg) |
52 | struct vnode *vp; | |
2d68027d MT |
53 | { |
54 | struct ktr_header *kth = ktrgetheader(KTR_SYSCALL); | |
55 | struct ktr_syscall *ktp; | |
56 | register len = sizeof(struct ktr_syscall) + (narg * sizeof(int)); | |
57 | int *argp, i; | |
58 | ||
f73d8bd6 | 59 | if (kth == NULL) |
2d68027d | 60 | return; |
2d68027d | 61 | MALLOC(ktp, struct ktr_syscall *, len, M_TEMP, M_WAITOK); |
2d68027d MT |
62 | ktp->ktr_code = code; |
63 | ktp->ktr_narg = narg; | |
64 | argp = (int *)((char *)ktp + sizeof(struct ktr_syscall)); | |
65 | for (i = 0; i < narg; i++) | |
66 | *argp++ = u.u_arg[i]; | |
67 | kth->ktr_buf = (caddr_t)ktp; | |
68 | kth->ktr_len = len; | |
c4ec2128 | 69 | ktrwrite(vp, kth); |
2d68027d MT |
70 | FREE(ktp, M_TEMP); |
71 | FREE(kth, M_TEMP); | |
72 | } | |
73 | ||
c4ec2128 KM |
74 | ktrsysret(vp, code) |
75 | struct vnode *vp; | |
2d68027d MT |
76 | { |
77 | struct ktr_header *kth = ktrgetheader(KTR_SYSRET); | |
78 | struct ktr_sysret *ktp; | |
79 | ||
f73d8bd6 | 80 | if (kth == NULL) |
2d68027d | 81 | return; |
2d68027d MT |
82 | MALLOC(ktp, struct ktr_sysret *, sizeof(struct ktr_sysret), |
83 | M_TEMP , M_WAITOK); | |
2d68027d MT |
84 | ktp->ktr_code = code; |
85 | ktp->ktr_eosys = u.u_eosys; | |
86 | ktp->ktr_error = u.u_error; | |
87 | ktp->ktr_retval = u.u_r.r_val1; /* what about val2 ? */ | |
88 | ||
89 | kth->ktr_buf = (caddr_t)ktp; | |
90 | kth->ktr_len = sizeof(struct ktr_sysret); | |
91 | ||
c4ec2128 | 92 | ktrwrite(vp, kth); |
2d68027d MT |
93 | FREE(ktp, M_TEMP); |
94 | FREE(kth, M_TEMP); | |
95 | } | |
96 | ||
c4ec2128 KM |
97 | ktrnamei(vp, path) |
98 | struct vnode *vp; | |
2d68027d MT |
99 | char *path; |
100 | { | |
101 | struct ktr_header *kth = ktrgetheader(KTR_NAMEI); | |
102 | ||
f73d8bd6 | 103 | if (kth == NULL) |
2d68027d | 104 | return; |
2d68027d MT |
105 | kth->ktr_len = strlen(path); |
106 | kth->ktr_buf = path; | |
107 | ||
c4ec2128 | 108 | ktrwrite(vp, kth); |
2d68027d MT |
109 | FREE(kth, M_TEMP); |
110 | } | |
111 | ||
c4ec2128 KM |
112 | ktrgenio(vp, fd, rw, iov, len) |
113 | struct vnode *vp; | |
f73d8bd6 MT |
114 | enum uio_rw rw; |
115 | register struct iovec *iov; | |
116 | { | |
117 | struct ktr_header *kth = ktrgetheader(KTR_GENIO); | |
118 | register struct ktr_genio *ktp; | |
119 | register caddr_t cp; | |
120 | register int resid = len, cnt; | |
121 | ||
122 | if (kth == NULL || u.u_error) | |
123 | return; | |
124 | MALLOC(ktp, struct ktr_genio *, sizeof(struct ktr_genio) + len, | |
125 | M_TEMP, M_WAITOK); | |
f73d8bd6 MT |
126 | ktp->ktr_fd = fd; |
127 | ktp->ktr_rw = rw; | |
128 | cp = (caddr_t)((char *)ktp + sizeof (struct ktr_genio)); | |
129 | while (resid > 0) { | |
130 | if ((cnt = iov->iov_len) > resid) | |
131 | cnt = resid; | |
132 | if (copyin(iov->iov_base, cp, cnt)) | |
133 | goto done; | |
134 | cp += cnt; | |
135 | resid -= cnt; | |
136 | iov++; | |
137 | } | |
138 | kth->ktr_buf = (caddr_t)ktp; | |
139 | kth->ktr_len = sizeof (struct ktr_genio) + len; | |
140 | ||
c4ec2128 | 141 | ktrwrite(vp, kth); |
f73d8bd6 MT |
142 | done: |
143 | FREE(kth, M_TEMP); | |
144 | FREE(ktp, M_TEMP); | |
145 | } | |
146 | ||
2d68027d MT |
147 | /* |
148 | * ktrace system call | |
149 | */ | |
150 | ktrace() | |
151 | { | |
2d68027d MT |
152 | register struct a { |
153 | char *fname; | |
154 | int ops; | |
155 | int facs; | |
f73d8bd6 | 156 | int pid; |
2d68027d | 157 | } *uap = (struct a *)u.u_ap; |
c4ec2128 | 158 | register struct vnode *vp = NULL; |
2d68027d MT |
159 | register struct nameidata *ndp = &u.u_nd; |
160 | register struct proc *p; | |
161 | struct pgrp *pg; | |
162 | register int ops = uap->ops&0x3; | |
163 | register int facs = uap->facs; | |
f73d8bd6 | 164 | register int ret = 0; |
2d68027d MT |
165 | |
166 | /* | |
167 | * Until security implications are thought through, | |
f73d8bd6 | 168 | * limit tracing to root (unless ktrace_nocheck is set). |
2d68027d | 169 | */ |
849cbd39 | 170 | if (!ktrace_nocheck && (u.u_error = suser(u.u_cred, &u.u_acflag))) |
2d68027d | 171 | return; |
2d68027d MT |
172 | if (ops != KTROP_CLEAR) { |
173 | /* | |
174 | * an operation which requires a file argument. | |
175 | */ | |
2d68027d MT |
176 | ndp->ni_segflg = UIO_USERSPACE; |
177 | ndp->ni_dirp = uap->fname; | |
c4ec2128 | 178 | if (u.u_error = vn_open(ndp, FREAD|FWRITE, 0)) |
2d68027d | 179 | return; |
c4ec2128 KM |
180 | vp = ndp->ni_vp; |
181 | if (vp->v_type != VREG) { | |
2d68027d | 182 | u.u_error = EACCES; |
c4ec2128 | 183 | vrele(vp); |
2d68027d MT |
184 | return; |
185 | } | |
2d68027d MT |
186 | } |
187 | /* | |
188 | * Clear all uses of the tracefile | |
189 | */ | |
190 | if (ops == KTROP_CLEARFILE) { | |
191 | for (p = allproc; p != NULL; p = p->p_nxt) { | |
c4ec2128 | 192 | if (p->p_tracep == vp) { |
2d68027d MT |
193 | p->p_flag &= ~SKTR; |
194 | p->p_tracep = NULL; | |
195 | p->p_traceflag = 0; | |
c4ec2128 | 196 | vrele(vp); |
2d68027d MT |
197 | } |
198 | } | |
199 | goto done; | |
200 | } | |
201 | ||
202 | /* | |
203 | * need something to (un)trace | |
204 | */ | |
205 | if (!facs) { | |
206 | u.u_error = EINVAL; | |
207 | goto done; | |
208 | } | |
209 | ||
210 | if (uap->pid < 0) { | |
211 | pg = pgfind(-uap->pid); | |
212 | if (pg == NULL) { | |
213 | u.u_error = ESRCH; | |
214 | goto done; | |
215 | } | |
216 | for (p = pg->pg_mem; p != NULL; p = p->p_pgrpnxt) | |
217 | if (uap->ops&KTROP_INHERITFLAG) | |
c4ec2128 | 218 | ret |= ktrsetchildren(p, ops, facs, vp); |
2d68027d | 219 | else |
c4ec2128 | 220 | ret |= ktrops(p, ops, facs, vp); |
2d68027d MT |
221 | |
222 | } else { | |
223 | p = pfind(uap->pid); | |
224 | if (p == NULL) { | |
225 | u.u_error = ESRCH; | |
226 | goto done; | |
227 | } | |
228 | if (uap->ops&KTROP_INHERITFLAG) | |
c4ec2128 | 229 | ret |= ktrsetchildren(p, ops, facs, vp); |
2d68027d | 230 | else |
c4ec2128 | 231 | ret |= ktrops(p, ops, facs, vp); |
2d68027d | 232 | } |
f73d8bd6 MT |
233 | if (!ret) |
234 | u.u_error = EPERM; | |
2d68027d | 235 | done: |
c4ec2128 KM |
236 | if (vp != NULL) |
237 | vrele(vp); | |
2d68027d MT |
238 | } |
239 | ||
c4ec2128 | 240 | ktrops(p, ops, facs, vp) |
2d68027d | 241 | struct proc *p; |
c4ec2128 | 242 | struct vnode *vp; |
2d68027d | 243 | { |
f73d8bd6 MT |
244 | |
245 | if (u.u_uid && u.u_uid != p->p_uid) | |
246 | return 0; | |
2d68027d | 247 | if (ops == KTROP_SET) { |
c4ec2128 | 248 | if (p->p_tracep != vp) { |
2d68027d MT |
249 | /* |
250 | * if trace file already in use, relinquish | |
251 | */ | |
252 | if (p->p_tracep != NULL) | |
c4ec2128 KM |
253 | vrele(p->p_tracep); |
254 | if (vp->v_count == 0) | |
255 | panic("ktrace: bad vnode"); | |
256 | p->p_tracep = vp; | |
2d68027d MT |
257 | } |
258 | p->p_traceflag |= facs; | |
259 | } else { | |
260 | /* KTROP_CLEAR */ | |
261 | if ((p->p_traceflag &= ~facs) == 0) { | |
262 | if (p->p_tracep != NULL) { | |
c4ec2128 | 263 | vrele(p->p_tracep); |
2d68027d MT |
264 | p->p_tracep = NULL; |
265 | } | |
f73d8bd6 | 266 | p->p_flag &= ~SKTR; |
2d68027d MT |
267 | } |
268 | } | |
f73d8bd6 MT |
269 | |
270 | return 1; | |
2d68027d | 271 | } |
f73d8bd6 | 272 | |
c4ec2128 | 273 | ktrsetchildren(top, ops, facs, vp) |
2d68027d | 274 | struct proc *top; |
c4ec2128 | 275 | struct vnode *vp; |
2d68027d MT |
276 | { |
277 | register struct proc *p; | |
278 | register int ndx; | |
f73d8bd6 | 279 | register int ret = 0; |
2d68027d MT |
280 | |
281 | p = top; | |
282 | for (;;) { | |
c4ec2128 | 283 | if ((ret |= ktrops(p, ops, facs, vp)) && ops == KTROP_SET) |
2d68027d | 284 | p->p_flag |= SKTR; |
2d68027d MT |
285 | /* |
286 | * If this process has children, descend to them next, | |
287 | * otherwise do any siblings, and if done with this level, | |
288 | * follow back up the tree (but not past top). | |
289 | */ | |
290 | if (p->p_cptr) | |
291 | p = p->p_cptr; | |
292 | else if (p == top) | |
f73d8bd6 | 293 | return ret; |
2d68027d MT |
294 | else if (p->p_osptr) |
295 | p = p->p_osptr; | |
296 | else for (;;) { | |
297 | p = p->p_pptr; | |
298 | if (p == top) | |
f73d8bd6 | 299 | return ret; |
2d68027d MT |
300 | if (p->p_osptr) { |
301 | p = p->p_osptr; | |
302 | break; | |
303 | } | |
304 | } | |
305 | } | |
f73d8bd6 | 306 | /*NOTREACHED*/ |
2d68027d MT |
307 | } |
308 | ||
c4ec2128 KM |
309 | ktrwrite(vp, kth) |
310 | struct vnode *vp; | |
311 | register struct ktr_header *kth; | |
2d68027d | 312 | { |
c4ec2128 KM |
313 | struct uio auio; |
314 | struct iovec aiov[2]; | |
315 | int offset, error; | |
316 | ||
317 | if (vp == NULL) | |
f73d8bd6 | 318 | return; |
c4ec2128 KM |
319 | auio.uio_iov = &aiov[0]; |
320 | auio.uio_offset = 0; | |
321 | auio.uio_segflg = UIO_SYSSPACE; | |
322 | auio.uio_rw = UIO_WRITE; | |
323 | aiov[0].iov_base = (caddr_t)kth; | |
324 | aiov[0].iov_len = sizeof(struct ktr_header); | |
325 | auio.uio_resid = sizeof(struct ktr_header); | |
326 | auio.uio_iovcnt = 1; | |
2d68027d | 327 | if (kth->ktr_len > 0) { |
c4ec2128 KM |
328 | auio.uio_iovcnt++; |
329 | aiov[1].iov_base = kth->ktr_buf; | |
330 | aiov[1].iov_len = kth->ktr_len; | |
331 | auio.uio_resid += kth->ktr_len; | |
2d68027d | 332 | } |
c4ec2128 | 333 | error = VOP_WRITE(vp, &auio, &offset, IO_UNIT|IO_APPEND, u.u_cred); |
2d68027d | 334 | } |
2d68027d | 335 | #endif |