386BSD 0.1 development
[unix-history] / usr / src / sys.386bsd / kern / kern_ktrace.c
CommitLineData
b688fc87
WJ
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, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * @(#)kern_ktrace.c 7.15 (Berkeley) 6/21/91
34 */
35
36#ifdef KTRACE
37
38#include "param.h"
39#include "proc.h"
40#include "file.h"
41#include "namei.h"
42#include "vnode.h"
43#include "ktrace.h"
44#include "malloc.h"
45#include "syslog.h"
46
47struct ktr_header *
48ktrgetheader(type)
49{
50 register struct ktr_header *kth;
51 struct proc *p = curproc; /* XXX */
52
53 MALLOC(kth, struct ktr_header *, sizeof (struct ktr_header),
54 M_TEMP, M_WAITOK);
55 kth->ktr_type = type;
56 microtime(&kth->ktr_time);
57 kth->ktr_pid = p->p_pid;
58 bcopy(p->p_comm, kth->ktr_comm, MAXCOMLEN);
59 return (kth);
60}
61
62ktrsyscall(vp, code, narg, args)
63 struct vnode *vp;
64 int code, narg, args[];
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 MALLOC(ktp, struct ktr_syscall *, len, M_TEMP, M_WAITOK);
72 ktp->ktr_code = code;
73 ktp->ktr_narg = narg;
74 argp = (int *)((char *)ktp + sizeof(struct ktr_syscall));
75 for (i = 0; i < narg; i++)
76 *argp++ = args[i];
77 kth->ktr_buf = (caddr_t)ktp;
78 kth->ktr_len = len;
79 ktrwrite(vp, kth);
80 FREE(ktp, M_TEMP);
81 FREE(kth, M_TEMP);
82}
83
84ktrsysret(vp, code, error, retval)
85 struct vnode *vp;
86 int code, error, retval;
87{
88 struct ktr_header *kth = ktrgetheader(KTR_SYSRET);
89 struct ktr_sysret ktp;
90
91 ktp.ktr_code = code;
92 ktp.ktr_error = error;
93 ktp.ktr_retval = retval; /* what about val2 ? */
94
95 kth->ktr_buf = (caddr_t)&ktp;
96 kth->ktr_len = sizeof(struct ktr_sysret);
97
98 ktrwrite(vp, kth);
99 FREE(kth, M_TEMP);
100}
101
102ktrnamei(vp, path)
103 struct vnode *vp;
104 char *path;
105{
106 struct ktr_header *kth = ktrgetheader(KTR_NAMEI);
107
108 kth->ktr_len = strlen(path);
109 kth->ktr_buf = path;
110
111 ktrwrite(vp, kth);
112 FREE(kth, M_TEMP);
113}
114
115ktrgenio(vp, fd, rw, iov, len, error)
116 struct vnode *vp;
117 int fd;
118 enum uio_rw rw;
119 register struct iovec *iov;
120{
121 struct ktr_header *kth = ktrgetheader(KTR_GENIO);
122 register struct ktr_genio *ktp;
123 register caddr_t cp;
124 register int resid = len, cnt;
125
126 if (error)
127 return;
128 MALLOC(ktp, struct ktr_genio *, sizeof(struct ktr_genio) + len,
129 M_TEMP, M_WAITOK);
130 ktp->ktr_fd = fd;
131 ktp->ktr_rw = rw;
132 cp = (caddr_t)((char *)ktp + sizeof (struct ktr_genio));
133 while (resid > 0) {
134 if ((cnt = iov->iov_len) > resid)
135 cnt = resid;
136 if (copyin(iov->iov_base, cp, (unsigned)cnt))
137 goto done;
138 cp += cnt;
139 resid -= cnt;
140 iov++;
141 }
142 kth->ktr_buf = (caddr_t)ktp;
143 kth->ktr_len = sizeof (struct ktr_genio) + len;
144
145 ktrwrite(vp, kth);
146done:
147 FREE(kth, M_TEMP);
148 FREE(ktp, M_TEMP);
149}
150
151ktrpsig(vp, sig, action, mask, code)
152 struct vnode *vp;
153 sig_t action;
154{
155 struct ktr_header *kth = ktrgetheader(KTR_PSIG);
156 struct ktr_psig kp;
157
158 kp.signo = (char)sig;
159 kp.action = action;
160 kp.mask = mask;
161 kp.code = code;
162 kth->ktr_buf = (caddr_t)&kp;
163 kth->ktr_len = sizeof (struct ktr_psig);
164
165 ktrwrite(vp, kth);
166 FREE(kth, M_TEMP);
167}
168
169/* Interface and common routines */
170
171/*
172 * ktrace system call
173 */
174/* ARGSUSED */
175ktrace(curp, uap, retval)
176 struct proc *curp;
177 register struct args {
178 char *fname;
179 int ops;
180 int facs;
181 int pid;
182 } *uap;
183 int *retval;
184{
185 register struct vnode *vp = NULL;
186 register struct proc *p;
187 struct pgrp *pg;
188 int facs = uap->facs & ~KTRFAC_ROOT;
189 int ops = KTROP(uap->ops);
190 int descend = uap->ops & KTRFLAG_DESCEND;
191 int ret = 0;
192 int error = 0;
193 struct nameidata nd;
194
195 if (ops != KTROP_CLEAR) {
196 /*
197 * an operation which requires a file argument.
198 */
199 nd.ni_segflg = UIO_USERSPACE;
200 nd.ni_dirp = uap->fname;
201 if (error = vn_open(&nd, curp, FREAD|FWRITE, 0))
202 return (error);
203 vp = nd.ni_vp;
204 VOP_UNLOCK(vp);
205 if (vp->v_type != VREG) {
206 (void) vn_close(vp, FREAD|FWRITE, curp->p_ucred, curp);
207 return (EACCES);
208 }
209 }
210 /*
211 * Clear all uses of the tracefile
212 */
213 if (ops == KTROP_CLEARFILE) {
214 for (p = allproc; p != NULL; p = p->p_nxt) {
215 if (p->p_tracep == vp) {
216 if (ktrcanset(curp, p)) {
217 p->p_tracep = NULL;
218 p->p_traceflag = 0;
219 (void) vn_close(vp, FREAD|FWRITE,
220 p->p_ucred, p);
221 } else
222 error = EPERM;
223 }
224 }
225 goto done;
226 }
227 /*
228 * need something to (un)trace (XXX - why is this here?)
229 */
230 if (!facs) {
231 error = EINVAL;
232 goto done;
233 }
234 /*
235 * do it
236 */
237 if (uap->pid < 0) {
238 /*
239 * by process group
240 */
241 pg = pgfind(-uap->pid);
242 if (pg == NULL) {
243 error = ESRCH;
244 goto done;
245 }
246 for (p = pg->pg_mem; p != NULL; p = p->p_pgrpnxt)
247 if (descend)
248 ret |= ktrsetchildren(curp, p, ops, facs, vp);
249 else
250 ret |= ktrops(curp, p, ops, facs, vp);
251
252 } else {
253 /*
254 * by pid
255 */
256 p = pfind(uap->pid);
257 if (p == NULL) {
258 error = ESRCH;
259 goto done;
260 }
261 if (descend)
262 ret |= ktrsetchildren(curp, p, ops, facs, vp);
263 else
264 ret |= ktrops(curp, p, ops, facs, vp);
265 }
266 if (!ret)
267 error = EPERM;
268done:
269 if (vp != NULL)
270 (void) vn_close(vp, FWRITE, curp->p_ucred, curp);
271 return (error);
272}
273
274ktrops(curp, p, ops, facs, vp)
275 struct proc *curp, *p;
276 struct vnode *vp;
277{
278
279 if (!ktrcanset(curp, p))
280 return (0);
281 if (ops == KTROP_SET) {
282 if (p->p_tracep != vp) {
283 /*
284 * if trace file already in use, relinquish
285 */
286 if (p->p_tracep != NULL)
287 vrele(p->p_tracep);
288 VREF(vp);
289 p->p_tracep = vp;
290 }
291 p->p_traceflag |= facs;
292 if (curp->p_ucred->cr_uid == 0)
293 p->p_traceflag |= KTRFAC_ROOT;
294 } else {
295 /* KTROP_CLEAR */
296 if (((p->p_traceflag &= ~facs) & KTRFAC_MASK) == 0) {
297 /* no more tracing */
298 p->p_traceflag = 0;
299 if (p->p_tracep != NULL) {
300 vrele(p->p_tracep);
301 p->p_tracep = NULL;
302 }
303 }
304 }
305
306 return (1);
307}
308
309ktrsetchildren(curp, top, ops, facs, vp)
310 struct proc *curp, *top;
311 struct vnode *vp;
312{
313 register struct proc *p;
314 register int ret = 0;
315
316 p = top;
317 for (;;) {
318 ret |= ktrops(curp, p, ops, facs, vp);
319 /*
320 * If this process has children, descend to them next,
321 * otherwise do any siblings, and if done with this level,
322 * follow back up the tree (but not past top).
323 */
324 if (p->p_cptr)
325 p = p->p_cptr;
326 else if (p == top)
327 return (ret);
328 else if (p->p_osptr)
329 p = p->p_osptr;
330 else for (;;) {
331 p = p->p_pptr;
332 if (p == top)
333 return (ret);
334 if (p->p_osptr) {
335 p = p->p_osptr;
336 break;
337 }
338 }
339 }
340 /*NOTREACHED*/
341}
342
343ktrwrite(vp, kth)
344 struct vnode *vp;
345 register struct ktr_header *kth;
346{
347 struct uio auio;
348 struct iovec aiov[2];
349 register struct proc *p = curproc; /* XXX */
350 int error;
351
352 if (vp == NULL)
353 return;
354 auio.uio_iov = &aiov[0];
355 auio.uio_offset = 0;
356 auio.uio_segflg = UIO_SYSSPACE;
357 auio.uio_rw = UIO_WRITE;
358 aiov[0].iov_base = (caddr_t)kth;
359 aiov[0].iov_len = sizeof(struct ktr_header);
360 auio.uio_resid = sizeof(struct ktr_header);
361 auio.uio_iovcnt = 1;
362 auio.uio_procp = (struct proc *)0;
363 if (kth->ktr_len > 0) {
364 auio.uio_iovcnt++;
365 aiov[1].iov_base = kth->ktr_buf;
366 aiov[1].iov_len = kth->ktr_len;
367 auio.uio_resid += kth->ktr_len;
368 }
369 VOP_LOCK(vp);
370 error = VOP_WRITE(vp, &auio, IO_UNIT|IO_APPEND, p->p_ucred);
371 VOP_UNLOCK(vp);
372 if (!error)
373 return;
374 /*
375 * If error encountered, give up tracing on this vnode.
376 */
377 log(LOG_NOTICE, "ktrace write failed, errno %d, tracing stopped\n",
378 error);
379 for (p = allproc; p != NULL; p = p->p_nxt) {
380 if (p->p_tracep == vp) {
381 p->p_tracep = NULL;
382 p->p_traceflag = 0;
383 vrele(vp);
384 }
385 }
386}
387
388/*
389 * Return true if caller has permission to set the ktracing state
390 * of target. Essentially, the target can't possess any
391 * more permissions than the caller. KTRFAC_ROOT signifies that
392 * root previously set the tracing status on the target process, and
393 * so, only root may further change it.
394 *
395 * TODO: check groups. use caller effective gid.
396 */
397ktrcanset(callp, targetp)
398 struct proc *callp, *targetp;
399{
400 register struct pcred *caller = callp->p_cred;
401 register struct pcred *target = targetp->p_cred;
402
403 if ((caller->pc_ucred->cr_uid == target->p_ruid &&
404 target->p_ruid == target->p_svuid &&
405 caller->p_rgid == target->p_rgid && /* XXX */
406 target->p_rgid == target->p_svgid &&
407 (targetp->p_traceflag & KTRFAC_ROOT) == 0) ||
408 caller->pc_ucred->cr_uid == 0)
409 return (1);
410
411 return (0);
412}
413
414#endif