This commit was generated by cvs2svn to track changes on a CVS vendor
[unix-history] / sys / kern / kern_ktrace.c
CommitLineData
15637ed4
RG
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 *
600f7f07
RG
33 * from: @(#)kern_ktrace.c 7.15 (Berkeley) 6/21/91
34 * $Id$
15637ed4
RG
35 */
36
37#ifdef KTRACE
38
39#include "param.h"
dd18dc33 40#include "systm.h"
15637ed4
RG
41#include "proc.h"
42#include "file.h"
43#include "namei.h"
44#include "vnode.h"
45#include "ktrace.h"
46#include "malloc.h"
47#include "syslog.h"
48
49struct ktr_header *
50ktrgetheader(type)
51{
52 register struct ktr_header *kth;
53 struct proc *p = curproc; /* XXX */
54
55 MALLOC(kth, struct ktr_header *, sizeof (struct ktr_header),
56 M_TEMP, M_WAITOK);
57 kth->ktr_type = type;
58 microtime(&kth->ktr_time);
59 kth->ktr_pid = p->p_pid;
60 bcopy(p->p_comm, kth->ktr_comm, MAXCOMLEN);
61 return (kth);
62}
63
64ktrsyscall(vp, code, narg, args)
65 struct vnode *vp;
66 int code, narg, args[];
67{
68 struct ktr_header *kth = ktrgetheader(KTR_SYSCALL);
69 struct ktr_syscall *ktp;
70 register len = sizeof(struct ktr_syscall) + (narg * sizeof(int));
71 int *argp, i;
72
73 MALLOC(ktp, struct ktr_syscall *, len, M_TEMP, M_WAITOK);
74 ktp->ktr_code = code;
75 ktp->ktr_narg = narg;
76 argp = (int *)((char *)ktp + sizeof(struct ktr_syscall));
77 for (i = 0; i < narg; i++)
78 *argp++ = args[i];
79 kth->ktr_buf = (caddr_t)ktp;
80 kth->ktr_len = len;
81 ktrwrite(vp, kth);
82 FREE(ktp, M_TEMP);
83 FREE(kth, M_TEMP);
84}
85
86ktrsysret(vp, code, error, retval)
87 struct vnode *vp;
88 int code, error, retval;
89{
90 struct ktr_header *kth = ktrgetheader(KTR_SYSRET);
91 struct ktr_sysret ktp;
92
93 ktp.ktr_code = code;
94 ktp.ktr_error = error;
95 ktp.ktr_retval = retval; /* what about val2 ? */
96
97 kth->ktr_buf = (caddr_t)&ktp;
98 kth->ktr_len = sizeof(struct ktr_sysret);
99
100 ktrwrite(vp, kth);
101 FREE(kth, M_TEMP);
102}
103
104ktrnamei(vp, path)
105 struct vnode *vp;
106 char *path;
107{
108 struct ktr_header *kth = ktrgetheader(KTR_NAMEI);
109
110 kth->ktr_len = strlen(path);
111 kth->ktr_buf = path;
112
113 ktrwrite(vp, kth);
114 FREE(kth, M_TEMP);
115}
116
117ktrgenio(vp, fd, rw, iov, len, error)
118 struct vnode *vp;
119 int fd;
120 enum uio_rw rw;
121 register struct iovec *iov;
122{
123 struct ktr_header *kth = ktrgetheader(KTR_GENIO);
124 register struct ktr_genio *ktp;
125 register caddr_t cp;
126 register int resid = len, cnt;
127
128 if (error)
129 return;
130 MALLOC(ktp, struct ktr_genio *, sizeof(struct ktr_genio) + len,
131 M_TEMP, M_WAITOK);
132 ktp->ktr_fd = fd;
133 ktp->ktr_rw = rw;
134 cp = (caddr_t)((char *)ktp + sizeof (struct ktr_genio));
135 while (resid > 0) {
136 if ((cnt = iov->iov_len) > resid)
137 cnt = resid;
138 if (copyin(iov->iov_base, cp, (unsigned)cnt))
139 goto done;
140 cp += cnt;
141 resid -= cnt;
142 iov++;
143 }
144 kth->ktr_buf = (caddr_t)ktp;
145 kth->ktr_len = sizeof (struct ktr_genio) + len;
146
147 ktrwrite(vp, kth);
148done:
149 FREE(kth, M_TEMP);
150 FREE(ktp, M_TEMP);
151}
152
153ktrpsig(vp, sig, action, mask, code)
154 struct vnode *vp;
155 sig_t action;
156{
157 struct ktr_header *kth = ktrgetheader(KTR_PSIG);
158 struct ktr_psig kp;
159
160 kp.signo = (char)sig;
161 kp.action = action;
162 kp.mask = mask;
163 kp.code = code;
164 kth->ktr_buf = (caddr_t)&kp;
165 kth->ktr_len = sizeof (struct ktr_psig);
166
167 ktrwrite(vp, kth);
168 FREE(kth, M_TEMP);
169}
170
171/* Interface and common routines */
172
173/*
174 * ktrace system call
175 */
3c7eb27c
DG
176
177struct ktrace_args {
178 char *fname;
179 int ops;
180 int facs;
181 int pid;
182};
183
15637ed4
RG
184/* ARGSUSED */
185ktrace(curp, uap, retval)
186 struct proc *curp;
3c7eb27c 187 register struct ktrace_args *uap;
15637ed4
RG
188 int *retval;
189{
190 register struct vnode *vp = NULL;
191 register struct proc *p;
192 struct pgrp *pg;
193 int facs = uap->facs & ~KTRFAC_ROOT;
194 int ops = KTROP(uap->ops);
195 int descend = uap->ops & KTRFLAG_DESCEND;
196 int ret = 0;
197 int error = 0;
198 struct nameidata nd;
199
200 if (ops != KTROP_CLEAR) {
201 /*
202 * an operation which requires a file argument.
203 */
204 nd.ni_segflg = UIO_USERSPACE;
205 nd.ni_dirp = uap->fname;
206 if (error = vn_open(&nd, curp, FREAD|FWRITE, 0))
207 return (error);
208 vp = nd.ni_vp;
209 VOP_UNLOCK(vp);
210 if (vp->v_type != VREG) {
211 (void) vn_close(vp, FREAD|FWRITE, curp->p_ucred, curp);
212 return (EACCES);
213 }
214 }
215 /*
216 * Clear all uses of the tracefile
217 */
218 if (ops == KTROP_CLEARFILE) {
219 for (p = allproc; p != NULL; p = p->p_nxt) {
220 if (p->p_tracep == vp) {
221 if (ktrcanset(curp, p)) {
222 p->p_tracep = NULL;
223 p->p_traceflag = 0;
224 (void) vn_close(vp, FREAD|FWRITE,
225 p->p_ucred, p);
226 } else
227 error = EPERM;
228 }
229 }
230 goto done;
231 }
232 /*
233 * need something to (un)trace (XXX - why is this here?)
234 */
235 if (!facs) {
236 error = EINVAL;
237 goto done;
238 }
239 /*
240 * do it
241 */
242 if (uap->pid < 0) {
243 /*
244 * by process group
245 */
246 pg = pgfind(-uap->pid);
247 if (pg == NULL) {
248 error = ESRCH;
249 goto done;
250 }
251 for (p = pg->pg_mem; p != NULL; p = p->p_pgrpnxt)
252 if (descend)
253 ret |= ktrsetchildren(curp, p, ops, facs, vp);
254 else
255 ret |= ktrops(curp, p, ops, facs, vp);
256
257 } else {
258 /*
259 * by pid
260 */
261 p = pfind(uap->pid);
262 if (p == NULL) {
263 error = ESRCH;
264 goto done;
265 }
266 if (descend)
267 ret |= ktrsetchildren(curp, p, ops, facs, vp);
268 else
269 ret |= ktrops(curp, p, ops, facs, vp);
270 }
271 if (!ret)
272 error = EPERM;
273done:
274 if (vp != NULL)
275 (void) vn_close(vp, FWRITE, curp->p_ucred, curp);
276 return (error);
277}
278
279ktrops(curp, p, ops, facs, vp)
280 struct proc *curp, *p;
281 struct vnode *vp;
282{
283
284 if (!ktrcanset(curp, p))
285 return (0);
286 if (ops == KTROP_SET) {
287 if (p->p_tracep != vp) {
288 /*
289 * if trace file already in use, relinquish
290 */
291 if (p->p_tracep != NULL)
292 vrele(p->p_tracep);
293 VREF(vp);
294 p->p_tracep = vp;
295 }
296 p->p_traceflag |= facs;
297 if (curp->p_ucred->cr_uid == 0)
298 p->p_traceflag |= KTRFAC_ROOT;
299 } else {
300 /* KTROP_CLEAR */
301 if (((p->p_traceflag &= ~facs) & KTRFAC_MASK) == 0) {
302 /* no more tracing */
303 p->p_traceflag = 0;
304 if (p->p_tracep != NULL) {
305 vrele(p->p_tracep);
306 p->p_tracep = NULL;
307 }
308 }
309 }
310
311 return (1);
312}
313
314ktrsetchildren(curp, top, ops, facs, vp)
315 struct proc *curp, *top;
316 struct vnode *vp;
317{
318 register struct proc *p;
319 register int ret = 0;
320
321 p = top;
322 for (;;) {
323 ret |= ktrops(curp, p, ops, facs, vp);
324 /*
325 * If this process has children, descend to them next,
326 * otherwise do any siblings, and if done with this level,
327 * follow back up the tree (but not past top).
328 */
329 if (p->p_cptr)
330 p = p->p_cptr;
331 else if (p == top)
332 return (ret);
333 else if (p->p_osptr)
334 p = p->p_osptr;
335 else for (;;) {
336 p = p->p_pptr;
337 if (p == top)
338 return (ret);
339 if (p->p_osptr) {
340 p = p->p_osptr;
341 break;
342 }
343 }
344 }
345 /*NOTREACHED*/
346}
347
348ktrwrite(vp, kth)
349 struct vnode *vp;
350 register struct ktr_header *kth;
351{
352 struct uio auio;
353 struct iovec aiov[2];
354 register struct proc *p = curproc; /* XXX */
355 int error;
356
357 if (vp == NULL)
358 return;
359 auio.uio_iov = &aiov[0];
360 auio.uio_offset = 0;
361 auio.uio_segflg = UIO_SYSSPACE;
362 auio.uio_rw = UIO_WRITE;
363 aiov[0].iov_base = (caddr_t)kth;
364 aiov[0].iov_len = sizeof(struct ktr_header);
365 auio.uio_resid = sizeof(struct ktr_header);
366 auio.uio_iovcnt = 1;
367 auio.uio_procp = (struct proc *)0;
368 if (kth->ktr_len > 0) {
369 auio.uio_iovcnt++;
370 aiov[1].iov_base = kth->ktr_buf;
371 aiov[1].iov_len = kth->ktr_len;
372 auio.uio_resid += kth->ktr_len;
373 }
374 VOP_LOCK(vp);
375 error = VOP_WRITE(vp, &auio, IO_UNIT|IO_APPEND, p->p_ucred);
376 VOP_UNLOCK(vp);
377 if (!error)
378 return;
379 /*
380 * If error encountered, give up tracing on this vnode.
381 */
382 log(LOG_NOTICE, "ktrace write failed, errno %d, tracing stopped\n",
383 error);
384 for (p = allproc; p != NULL; p = p->p_nxt) {
385 if (p->p_tracep == vp) {
386 p->p_tracep = NULL;
387 p->p_traceflag = 0;
388 vrele(vp);
389 }
390 }
391}
392
393/*
394 * Return true if caller has permission to set the ktracing state
395 * of target. Essentially, the target can't possess any
396 * more permissions than the caller. KTRFAC_ROOT signifies that
397 * root previously set the tracing status on the target process, and
398 * so, only root may further change it.
399 *
400 * TODO: check groups. use caller effective gid.
401 */
402ktrcanset(callp, targetp)
403 struct proc *callp, *targetp;
404{
405 register struct pcred *caller = callp->p_cred;
406 register struct pcred *target = targetp->p_cred;
407
408 if ((caller->pc_ucred->cr_uid == target->p_ruid &&
409 target->p_ruid == target->p_svuid &&
410 caller->p_rgid == target->p_rgid && /* XXX */
411 target->p_rgid == target->p_svgid &&
412 (targetp->p_traceflag & KTRFAC_ROOT) == 0) ||
413 caller->pc_ucred->cr_uid == 0)
414 return (1);
415
416 return (0);
417}
418
419#endif