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 | * | |
8b24ca5d | 17 | * @(#)kern_ktrace.c 7.6 (Berkeley) %G% |
2d68027d MT |
18 | */ |
19 | ||
20 | #ifdef KTRACE | |
21 | ||
22 | #include "param.h" | |
8b24ca5d | 23 | #include "syscontext.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 | 46 | kth->ktr_pid = u.u_procp->p_pid; |
a97cc92e | 47 | bcopy(u.u_procp->p_comm, kth->ktr_comm, MAXCOMLEN); |
2d68027d MT |
48 | return (kth); |
49 | } | |
50 | ||
8b24ca5d | 51 | ktrsyscall(vp, code, narg, args) |
c4ec2128 | 52 | struct vnode *vp; |
8b24ca5d | 53 | int code, narg, args[]; |
2d68027d MT |
54 | { |
55 | struct ktr_header *kth = ktrgetheader(KTR_SYSCALL); | |
56 | struct ktr_syscall *ktp; | |
57 | register len = sizeof(struct ktr_syscall) + (narg * sizeof(int)); | |
58 | int *argp, i; | |
59 | ||
f73d8bd6 | 60 | if (kth == NULL) |
2d68027d | 61 | return; |
2d68027d | 62 | MALLOC(ktp, struct ktr_syscall *, len, M_TEMP, M_WAITOK); |
2d68027d MT |
63 | ktp->ktr_code = code; |
64 | ktp->ktr_narg = narg; | |
65 | argp = (int *)((char *)ktp + sizeof(struct ktr_syscall)); | |
66 | for (i = 0; i < narg; i++) | |
8b24ca5d | 67 | *argp++ = args[i]; |
2d68027d MT |
68 | kth->ktr_buf = (caddr_t)ktp; |
69 | kth->ktr_len = len; | |
c4ec2128 | 70 | ktrwrite(vp, kth); |
2d68027d MT |
71 | FREE(ktp, M_TEMP); |
72 | FREE(kth, M_TEMP); | |
73 | } | |
74 | ||
8b24ca5d | 75 | ktrsysret(vp, code, error, retval) |
c4ec2128 | 76 | struct vnode *vp; |
8b24ca5d | 77 | int code, error, retval; |
2d68027d MT |
78 | { |
79 | struct ktr_header *kth = ktrgetheader(KTR_SYSRET); | |
a97cc92e | 80 | struct ktr_sysret ktp; |
2d68027d | 81 | |
f73d8bd6 | 82 | if (kth == NULL) |
2d68027d | 83 | return; |
a97cc92e | 84 | ktp.ktr_code = code; |
8b24ca5d KM |
85 | ktp.ktr_error = error; |
86 | ktp.ktr_retval = retval; /* what about val2 ? */ | |
2d68027d | 87 | |
a97cc92e | 88 | kth->ktr_buf = (caddr_t)&ktp; |
2d68027d MT |
89 | kth->ktr_len = sizeof(struct ktr_sysret); |
90 | ||
c4ec2128 | 91 | ktrwrite(vp, kth); |
2d68027d MT |
92 | FREE(kth, M_TEMP); |
93 | } | |
94 | ||
c4ec2128 KM |
95 | ktrnamei(vp, path) |
96 | struct vnode *vp; | |
2d68027d MT |
97 | char *path; |
98 | { | |
99 | struct ktr_header *kth = ktrgetheader(KTR_NAMEI); | |
100 | ||
f73d8bd6 | 101 | if (kth == NULL) |
2d68027d | 102 | return; |
2d68027d MT |
103 | kth->ktr_len = strlen(path); |
104 | kth->ktr_buf = path; | |
105 | ||
c4ec2128 | 106 | ktrwrite(vp, kth); |
2d68027d MT |
107 | FREE(kth, M_TEMP); |
108 | } | |
109 | ||
8b24ca5d | 110 | ktrgenio(vp, fd, rw, iov, len, error) |
c4ec2128 | 111 | struct vnode *vp; |
8b24ca5d | 112 | int fd; |
f73d8bd6 MT |
113 | enum uio_rw rw; |
114 | register struct iovec *iov; | |
115 | { | |
116 | struct ktr_header *kth = ktrgetheader(KTR_GENIO); | |
117 | register struct ktr_genio *ktp; | |
118 | register caddr_t cp; | |
119 | register int resid = len, cnt; | |
120 | ||
8b24ca5d | 121 | if (kth == NULL || error) |
f73d8bd6 MT |
122 | return; |
123 | MALLOC(ktp, struct ktr_genio *, sizeof(struct ktr_genio) + len, | |
124 | M_TEMP, M_WAITOK); | |
f73d8bd6 MT |
125 | ktp->ktr_fd = fd; |
126 | ktp->ktr_rw = rw; | |
127 | cp = (caddr_t)((char *)ktp + sizeof (struct ktr_genio)); | |
128 | while (resid > 0) { | |
129 | if ((cnt = iov->iov_len) > resid) | |
130 | cnt = resid; | |
e5e5e641 | 131 | if (copyin(iov->iov_base, cp, (unsigned)cnt)) |
f73d8bd6 MT |
132 | goto done; |
133 | cp += cnt; | |
134 | resid -= cnt; | |
135 | iov++; | |
136 | } | |
137 | kth->ktr_buf = (caddr_t)ktp; | |
138 | kth->ktr_len = sizeof (struct ktr_genio) + len; | |
139 | ||
c4ec2128 | 140 | ktrwrite(vp, kth); |
f73d8bd6 MT |
141 | done: |
142 | FREE(kth, M_TEMP); | |
143 | FREE(ktp, M_TEMP); | |
144 | } | |
145 | ||
a97cc92e MT |
146 | ktrpsig(vp, sig, action, mask, code) |
147 | struct vnode *vp; | |
148 | sig_t action; | |
149 | { | |
150 | struct ktr_header *kth = ktrgetheader(KTR_PSIG); | |
151 | struct ktr_psig kp; | |
152 | ||
153 | if (kth == NULL) | |
154 | return; | |
155 | kp.signo = (char)sig; | |
156 | kp.action = action; | |
157 | kp.mask = mask; | |
158 | kp.code = code; | |
159 | kth->ktr_buf = (caddr_t)&kp; | |
160 | kth->ktr_len = sizeof (struct ktr_psig); | |
161 | ||
162 | ktrwrite(vp, kth); | |
163 | FREE(kth, M_TEMP); | |
164 | } | |
165 | ||
166 | /* Interface and common routines */ | |
167 | ||
2d68027d MT |
168 | /* |
169 | * ktrace system call | |
170 | */ | |
8b24ca5d KM |
171 | /* ARGSUSED */ |
172 | ktrace(curp, uap, retval) | |
173 | struct proc *curp; | |
174 | register struct args { | |
2d68027d MT |
175 | char *fname; |
176 | int ops; | |
177 | int facs; | |
f73d8bd6 | 178 | int pid; |
8b24ca5d KM |
179 | } *uap; |
180 | int *retval; | |
181 | { | |
c4ec2128 | 182 | register struct vnode *vp = NULL; |
2d68027d MT |
183 | register struct nameidata *ndp = &u.u_nd; |
184 | register struct proc *p; | |
a97cc92e | 185 | register ops = KTROP(uap->ops); |
2d68027d | 186 | struct pgrp *pg; |
2d68027d | 187 | register int facs = uap->facs; |
f73d8bd6 | 188 | register int ret = 0; |
8b24ca5d | 189 | int error = 0; |
2d68027d MT |
190 | |
191 | /* | |
192 | * Until security implications are thought through, | |
f73d8bd6 | 193 | * limit tracing to root (unless ktrace_nocheck is set). |
2d68027d | 194 | */ |
8b24ca5d KM |
195 | if (!ktrace_nocheck && (error = suser(u.u_cred, &u.u_acflag))) |
196 | RETURN (error); | |
2d68027d MT |
197 | if (ops != KTROP_CLEAR) { |
198 | /* | |
199 | * an operation which requires a file argument. | |
200 | */ | |
2d68027d MT |
201 | ndp->ni_segflg = UIO_USERSPACE; |
202 | ndp->ni_dirp = uap->fname; | |
8b24ca5d KM |
203 | if (error = vn_open(ndp, FREAD|FWRITE, 0)) |
204 | RETURN (error); | |
c4ec2128 KM |
205 | vp = ndp->ni_vp; |
206 | if (vp->v_type != VREG) { | |
c4ec2128 | 207 | vrele(vp); |
8b24ca5d | 208 | RETURN (EACCES); |
2d68027d | 209 | } |
2d68027d MT |
210 | } |
211 | /* | |
212 | * Clear all uses of the tracefile | |
213 | */ | |
214 | if (ops == KTROP_CLEARFILE) { | |
215 | for (p = allproc; p != NULL; p = p->p_nxt) { | |
c4ec2128 | 216 | if (p->p_tracep == vp) { |
2d68027d MT |
217 | p->p_tracep = NULL; |
218 | p->p_traceflag = 0; | |
c4ec2128 | 219 | vrele(vp); |
2d68027d MT |
220 | } |
221 | } | |
222 | goto done; | |
223 | } | |
2d68027d MT |
224 | /* |
225 | * need something to (un)trace | |
226 | */ | |
227 | if (!facs) { | |
8b24ca5d | 228 | error = EINVAL; |
2d68027d MT |
229 | goto done; |
230 | } | |
a97cc92e MT |
231 | /* |
232 | * doit | |
233 | */ | |
2d68027d MT |
234 | if (uap->pid < 0) { |
235 | pg = pgfind(-uap->pid); | |
236 | if (pg == NULL) { | |
8b24ca5d | 237 | error = ESRCH; |
2d68027d MT |
238 | goto done; |
239 | } | |
240 | for (p = pg->pg_mem; p != NULL; p = p->p_pgrpnxt) | |
a97cc92e | 241 | if (uap->ops&KTRFLAG_DESCEND) |
c4ec2128 | 242 | ret |= ktrsetchildren(p, ops, facs, vp); |
2d68027d | 243 | else |
c4ec2128 | 244 | ret |= ktrops(p, ops, facs, vp); |
2d68027d MT |
245 | |
246 | } else { | |
247 | p = pfind(uap->pid); | |
248 | if (p == NULL) { | |
8b24ca5d | 249 | error = ESRCH; |
2d68027d MT |
250 | goto done; |
251 | } | |
a97cc92e | 252 | if (ops&KTRFLAG_DESCEND) |
c4ec2128 | 253 | ret |= ktrsetchildren(p, ops, facs, vp); |
2d68027d | 254 | else |
c4ec2128 | 255 | ret |= ktrops(p, ops, facs, vp); |
2d68027d | 256 | } |
f73d8bd6 | 257 | if (!ret) |
8b24ca5d | 258 | error = EPERM; |
2d68027d | 259 | done: |
c4ec2128 KM |
260 | if (vp != NULL) |
261 | vrele(vp); | |
8b24ca5d | 262 | RETURN (error); |
2d68027d MT |
263 | } |
264 | ||
c4ec2128 | 265 | ktrops(p, ops, facs, vp) |
2d68027d | 266 | struct proc *p; |
c4ec2128 | 267 | struct vnode *vp; |
2d68027d | 268 | { |
f73d8bd6 MT |
269 | |
270 | if (u.u_uid && u.u_uid != p->p_uid) | |
271 | return 0; | |
2d68027d | 272 | if (ops == KTROP_SET) { |
a97cc92e | 273 | if (p->p_tracep != vp) { |
2d68027d MT |
274 | /* |
275 | * if trace file already in use, relinquish | |
276 | */ | |
277 | if (p->p_tracep != NULL) | |
c4ec2128 | 278 | vrele(p->p_tracep); |
2c0d2f20 | 279 | VREF(vp); |
c4ec2128 | 280 | p->p_tracep = vp; |
2d68027d MT |
281 | } |
282 | p->p_traceflag |= facs; | |
283 | } else { | |
284 | /* KTROP_CLEAR */ | |
a97cc92e MT |
285 | if (((p->p_traceflag &= ~facs) & ~KTRFAC_INHERIT) == 0) { |
286 | /* no more tracing */ | |
287 | p->p_traceflag = 0; | |
2d68027d | 288 | if (p->p_tracep != NULL) { |
c4ec2128 | 289 | vrele(p->p_tracep); |
2d68027d MT |
290 | p->p_tracep = NULL; |
291 | } | |
2d68027d MT |
292 | } |
293 | } | |
f73d8bd6 MT |
294 | |
295 | return 1; | |
2d68027d | 296 | } |
f73d8bd6 | 297 | |
c4ec2128 | 298 | ktrsetchildren(top, ops, facs, vp) |
2d68027d | 299 | struct proc *top; |
c4ec2128 | 300 | struct vnode *vp; |
2d68027d MT |
301 | { |
302 | register struct proc *p; | |
f73d8bd6 | 303 | register int ret = 0; |
2d68027d MT |
304 | |
305 | p = top; | |
306 | for (;;) { | |
a97cc92e | 307 | ret |= ktrops(p, ops, facs, vp); |
2d68027d MT |
308 | /* |
309 | * If this process has children, descend to them next, | |
310 | * otherwise do any siblings, and if done with this level, | |
311 | * follow back up the tree (but not past top). | |
312 | */ | |
313 | if (p->p_cptr) | |
314 | p = p->p_cptr; | |
315 | else if (p == top) | |
f73d8bd6 | 316 | return ret; |
2d68027d MT |
317 | else if (p->p_osptr) |
318 | p = p->p_osptr; | |
319 | else for (;;) { | |
320 | p = p->p_pptr; | |
321 | if (p == top) | |
f73d8bd6 | 322 | return ret; |
2d68027d MT |
323 | if (p->p_osptr) { |
324 | p = p->p_osptr; | |
325 | break; | |
326 | } | |
327 | } | |
328 | } | |
f73d8bd6 | 329 | /*NOTREACHED*/ |
2d68027d MT |
330 | } |
331 | ||
c4ec2128 KM |
332 | ktrwrite(vp, kth) |
333 | struct vnode *vp; | |
334 | register struct ktr_header *kth; | |
2d68027d | 335 | { |
c4ec2128 KM |
336 | struct uio auio; |
337 | struct iovec aiov[2]; | |
e5e5e641 | 338 | struct proc *p; |
aeb44310 | 339 | int error; |
c4ec2128 KM |
340 | |
341 | if (vp == NULL) | |
f73d8bd6 | 342 | return; |
c4ec2128 KM |
343 | auio.uio_iov = &aiov[0]; |
344 | auio.uio_offset = 0; | |
345 | auio.uio_segflg = UIO_SYSSPACE; | |
346 | auio.uio_rw = UIO_WRITE; | |
347 | aiov[0].iov_base = (caddr_t)kth; | |
348 | aiov[0].iov_len = sizeof(struct ktr_header); | |
349 | auio.uio_resid = sizeof(struct ktr_header); | |
350 | auio.uio_iovcnt = 1; | |
2d68027d | 351 | if (kth->ktr_len > 0) { |
c4ec2128 KM |
352 | auio.uio_iovcnt++; |
353 | aiov[1].iov_base = kth->ktr_buf; | |
354 | aiov[1].iov_len = kth->ktr_len; | |
355 | auio.uio_resid += kth->ktr_len; | |
2d68027d | 356 | } |
aeb44310 KM |
357 | VOP_LOCK(vp); |
358 | error = VOP_WRITE(vp, &auio, IO_UNIT|IO_APPEND, u.u_cred); | |
359 | VOP_UNLOCK(vp); | |
e5e5e641 KM |
360 | if (!error) |
361 | return; | |
362 | /* | |
363 | * If error encountered, give up tracing on this vnode. | |
364 | */ | |
365 | uprintf("\ntrace write failed with errno %d, tracing stopped\n", error); | |
366 | for (p = allproc; p != NULL; p = p->p_nxt) { | |
367 | if (p->p_tracep == vp) { | |
368 | p->p_tracep = NULL; | |
369 | p->p_traceflag = 0; | |
370 | vrele(vp); | |
371 | } | |
372 | } | |
2d68027d | 373 | } |
2d68027d | 374 | #endif |