1 /* $OpenBSD: kern_ktrace.c,v 1.31 2003/09/01 18:06:03 henning Exp $ */
2 /* $NetBSD: kern_ktrace.c,v 1.23 1996/02/09 18:59:36 christos Exp $ */
3
4 /*
5 * Copyright (c) 1989, 1993
6 * The Regents of the University of California. All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 *
32 * @(#)kern_ktrace.c 8.2 (Berkeley) 9/23/93
33 */
34
35 #ifdef KTRACE
36
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/proc.h>
40 #include <sys/file.h>
41 #include <sys/namei.h>
42 #include <sys/vnode.h>
43 #include <sys/ktrace.h>
44 #include <sys/malloc.h>
45 #include <sys/syslog.h>
46
47 #include <sys/mount.h>
48 #include <sys/syscallargs.h>
49
50 #include <uvm/uvm_extern.h>
51
52 void ktrinitheader(struct ktr_header *, struct proc *, int);
53 int ktrops(struct proc *, struct proc *, int, int, struct vnode *);
54 int ktrsetchildren(struct proc *, struct proc *, int, int,
55 struct vnode *);
56 int ktrwrite(struct proc *, struct ktr_header *);
57 int ktrcanset(struct proc *, struct proc *);
58
59 /*
60 * Change the trace vnode in a correct way (to avoid races).
61 */
62 void
ktrsettracevnode(p,newvp)63 ktrsettracevnode(p, newvp)
64 struct proc *p;
65 struct vnode *newvp;
66 {
67 struct vnode *vp;
68
69 if (p->p_tracep == newvp) /* avoid work */
70 return;
71
72 if (newvp != NULL)
73 VREF(newvp);
74
75 vp = p->p_tracep;
76 p->p_tracep = newvp;
77
78 if (vp != NULL)
79 vrele(vp);
80 }
81
82 void
ktrinitheader(kth,p,type)83 ktrinitheader(kth, p, type)
84 struct ktr_header *kth;
85 struct proc *p;
86 int type;
87 {
88 bzero(kth, sizeof (struct ktr_header));
89 kth->ktr_type = type;
90 microtime(&kth->ktr_time);
91 kth->ktr_pid = p->p_pid;
92 bcopy(p->p_comm, kth->ktr_comm, MAXCOMLEN);
93 }
94
95 void
ktrsyscall(p,code,argsize,args)96 ktrsyscall(p, code, argsize, args)
97 struct proc *p;
98 register_t code;
99 size_t argsize;
100 register_t args[];
101 {
102 struct ktr_header kth;
103 struct ktr_syscall *ktp;
104 unsigned int len = sizeof(struct ktr_syscall) + argsize;
105 register_t *argp;
106 int i;
107
108 p->p_traceflag |= KTRFAC_ACTIVE;
109 ktrinitheader(&kth, p, KTR_SYSCALL);
110 ktp = malloc(len, M_TEMP, M_WAITOK);
111 ktp->ktr_code = code;
112 ktp->ktr_argsize = argsize;
113 argp = (register_t *)((char *)ktp + sizeof(struct ktr_syscall));
114 for (i = 0; i < (argsize / sizeof *argp); i++)
115 *argp++ = args[i];
116 kth.ktr_buf = (caddr_t)ktp;
117 kth.ktr_len = len;
118 ktrwrite(p, &kth);
119 free(ktp, M_TEMP);
120 p->p_traceflag &= ~KTRFAC_ACTIVE;
121 }
122
123 void
ktrsysret(p,code,error,retval)124 ktrsysret(p, code, error, retval)
125 struct proc *p;
126 register_t code;
127 int error;
128 register_t retval;
129 {
130 struct ktr_header kth;
131 struct ktr_sysret ktp;
132
133 p->p_traceflag |= KTRFAC_ACTIVE;
134 ktrinitheader(&kth, p, KTR_SYSRET);
135 ktp.ktr_code = code;
136 ktp.ktr_error = error;
137 ktp.ktr_retval = retval; /* what about val2 ? */
138
139 kth.ktr_buf = (caddr_t)&ktp;
140 kth.ktr_len = sizeof(struct ktr_sysret);
141
142 ktrwrite(p, &kth);
143 p->p_traceflag &= ~KTRFAC_ACTIVE;
144 }
145
146 void
ktrnamei(p,path)147 ktrnamei(p, path)
148 struct proc *p;
149 char *path;
150 {
151 struct ktr_header kth;
152
153 p->p_traceflag |= KTRFAC_ACTIVE;
154 ktrinitheader(&kth, p, KTR_NAMEI);
155 kth.ktr_len = strlen(path);
156 kth.ktr_buf = path;
157
158 ktrwrite(p, &kth);
159 p->p_traceflag &= ~KTRFAC_ACTIVE;
160 }
161
162 void
ktremul(p,emul)163 ktremul(p, emul)
164 struct proc *p;
165 char *emul;
166 {
167 struct ktr_header kth;
168
169 p->p_traceflag |= KTRFAC_ACTIVE;
170 ktrinitheader(&kth, p, KTR_EMUL);
171 kth.ktr_len = strlen(emul);
172 kth.ktr_buf = emul;
173
174 ktrwrite(p, &kth);
175 p->p_traceflag &= ~KTRFAC_ACTIVE;
176 }
177
178 void
ktrgenio(p,fd,rw,iov,len,error)179 ktrgenio(p, fd, rw, iov, len, error)
180 struct proc *p;
181 int fd;
182 enum uio_rw rw;
183 struct iovec *iov;
184 int len, error;
185 {
186 struct ktr_header kth;
187 struct ktr_genio *ktp;
188 caddr_t cp;
189 int resid = len, count;
190 int buflen;
191
192 if (error)
193 return;
194
195 p->p_traceflag |= KTRFAC_ACTIVE;
196
197 buflen = min(PAGE_SIZE, len + sizeof(struct ktr_genio));
198
199 ktrinitheader(&kth, p, KTR_GENIO);
200 ktp = malloc(buflen, M_TEMP, M_WAITOK);
201 ktp->ktr_fd = fd;
202 ktp->ktr_rw = rw;
203
204 kth.ktr_buf = (caddr_t)ktp;
205
206 cp = (caddr_t)((char *)ktp + sizeof (struct ktr_genio));
207 buflen -= sizeof(struct ktr_genio);
208
209 while (resid > 0) {
210 /*
211 * Don't allow this process to hog the cpu when doing
212 * huge I/O.
213 */
214 if (p->p_schedflags & PSCHED_SHOULDYIELD)
215 preempt(NULL);
216
217 count = min(iov->iov_len, buflen);
218 if (count > resid)
219 count = resid;
220 if (copyin(iov->iov_base, cp, count))
221 break;
222
223 kth.ktr_len = count + sizeof(struct ktr_genio);
224
225 if (ktrwrite(p, &kth) != 0)
226 break;
227
228 iov->iov_len -= count;
229 iov->iov_base = (caddr_t)iov->iov_base + count;
230
231 if (iov->iov_len == 0)
232 iov++;
233
234 resid -= count;
235 }
236
237 free(ktp, M_TEMP);
238 p->p_traceflag &= ~KTRFAC_ACTIVE;
239
240 }
241
242 void
ktrpsig(p,sig,action,mask,code,si)243 ktrpsig(p, sig, action, mask, code, si)
244 struct proc *p;
245 int sig;
246 sig_t action;
247 int mask, code;
248 siginfo_t *si;
249 {
250 struct ktr_header kth;
251 struct ktr_psig kp;
252
253 p->p_traceflag |= KTRFAC_ACTIVE;
254 ktrinitheader(&kth, p, KTR_PSIG);
255 kp.signo = (char)sig;
256 kp.action = action;
257 kp.mask = mask;
258 kp.code = code;
259 kp.si = *si;
260 kth.ktr_buf = (caddr_t)&kp;
261 kth.ktr_len = sizeof (struct ktr_psig);
262
263 ktrwrite(p, &kth);
264 p->p_traceflag &= ~KTRFAC_ACTIVE;
265 }
266
267 void
ktrcsw(p,out,user)268 ktrcsw(p, out, user)
269 struct proc *p;
270 int out, user;
271 {
272 struct ktr_header kth;
273 struct ktr_csw kc;
274
275 p->p_traceflag |= KTRFAC_ACTIVE;
276 ktrinitheader(&kth, p, KTR_CSW);
277 kc.out = out;
278 kc.user = user;
279 kth.ktr_buf = (caddr_t)&kc;
280 kth.ktr_len = sizeof (struct ktr_csw);
281
282 ktrwrite(p, &kth);
283 p->p_traceflag &= ~KTRFAC_ACTIVE;
284 }
285
286 /* Interface and common routines */
287
288 /*
289 * ktrace system call
290 */
291 /* ARGSUSED */
292 int
sys_ktrace(curp,v,retval)293 sys_ktrace(curp, v, retval)
294 struct proc *curp;
295 void *v;
296 register_t *retval;
297 {
298 struct sys_ktrace_args /* {
299 syscallarg(const char *) fname;
300 syscallarg(int) ops;
301 syscallarg(int) facs;
302 syscallarg(pid_t) pid;
303 } */ *uap = v;
304 struct vnode *vp = NULL;
305 struct proc *p = NULL;
306 struct pgrp *pg;
307 int facs = SCARG(uap, facs) & ~((unsigned) KTRFAC_ROOT);
308 int ops = KTROP(SCARG(uap, ops));
309 int descend = SCARG(uap, ops) & KTRFLAG_DESCEND;
310 int ret = 0;
311 int error = 0;
312 struct nameidata nd;
313
314 curp->p_traceflag |= KTRFAC_ACTIVE;
315 if (ops != KTROP_CLEAR) {
316 /*
317 * an operation which requires a file argument.
318 */
319 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, fname),
320 curp);
321 if ((error = vn_open(&nd, FREAD|FWRITE|O_NOFOLLOW, 0)) != 0) {
322 curp->p_traceflag &= ~KTRFAC_ACTIVE;
323 return (error);
324 }
325 vp = nd.ni_vp;
326
327 VOP_UNLOCK(vp, 0, curp);
328 if (vp->v_type != VREG) {
329 (void) vn_close(vp, FREAD|FWRITE, curp->p_ucred, curp);
330 curp->p_traceflag &= ~KTRFAC_ACTIVE;
331 return (EACCES);
332 }
333 }
334 /*
335 * Clear all uses of the tracefile
336 */
337 if (ops == KTROP_CLEARFILE) {
338 for (p = LIST_FIRST(&allproc); p; p = LIST_NEXT(p, p_list)) {
339 if (p->p_tracep == vp) {
340 if (ktrcanset(curp, p)) {
341 p->p_traceflag = 0;
342 ktrsettracevnode(p, NULL);
343 } else
344 error = EPERM;
345 }
346 }
347 goto done;
348 }
349 /*
350 * need something to (un)trace (XXX - why is this here?)
351 */
352 if (!facs) {
353 error = EINVAL;
354 goto done;
355 }
356 /*
357 * do it
358 */
359 if (SCARG(uap, pid) < 0) {
360 /*
361 * by process group
362 */
363 pg = pgfind(-SCARG(uap, pid));
364 if (pg == NULL) {
365 error = ESRCH;
366 goto done;
367 }
368 for (p = pg->pg_members.lh_first; p != 0; p = p->p_pglist.le_next)
369 if (descend)
370 ret |= ktrsetchildren(curp, p, ops, facs, vp);
371 else
372 ret |= ktrops(curp, p, ops, facs, vp);
373
374 } else {
375 /*
376 * by pid
377 */
378 p = pfind(SCARG(uap, pid));
379 if (p == NULL) {
380 error = ESRCH;
381 goto done;
382 }
383 if (descend)
384 ret |= ktrsetchildren(curp, p, ops, facs, vp);
385 else
386 ret |= ktrops(curp, p, ops, facs, vp);
387 }
388 if (!ret)
389 error = EPERM;
390 done:
391 if (vp != NULL)
392 (void) vn_close(vp, FWRITE, curp->p_ucred, curp);
393 curp->p_traceflag &= ~KTRFAC_ACTIVE;
394 return (error);
395 }
396
397 int
ktrops(curp,p,ops,facs,vp)398 ktrops(curp, p, ops, facs, vp)
399 struct proc *p, *curp;
400 int ops, facs;
401 struct vnode *vp;
402 {
403
404 if (!ktrcanset(curp, p))
405 return (0);
406 if (ops == KTROP_SET) {
407 ktrsettracevnode(p, vp);
408 p->p_traceflag |= facs;
409 if (curp->p_ucred->cr_uid == 0)
410 p->p_traceflag |= KTRFAC_ROOT;
411 } else {
412 /* KTROP_CLEAR */
413 if (((p->p_traceflag &= ~facs) & KTRFAC_MASK) == 0) {
414 /* no more tracing */
415 p->p_traceflag = 0;
416 ktrsettracevnode(p, NULL);
417 }
418 }
419
420 /*
421 * Emit an emulation record, every time there is a ktrace
422 * change/attach request.
423 */
424 if (KTRPOINT(p, KTR_EMUL))
425 ktremul(p, p->p_emul->e_name);
426
427 return (1);
428 }
429
430 int
ktrsetchildren(curp,top,ops,facs,vp)431 ktrsetchildren(curp, top, ops, facs, vp)
432 struct proc *curp, *top;
433 int ops, facs;
434 struct vnode *vp;
435 {
436 struct proc *p;
437 int ret = 0;
438
439 p = top;
440 for (;;) {
441 ret |= ktrops(curp, p, ops, facs, vp);
442 /*
443 * If this process has children, descend to them next,
444 * otherwise do any siblings, and if done with this level,
445 * follow back up the tree (but not past top).
446 */
447 if (p->p_children.lh_first)
448 p = p->p_children.lh_first;
449 else for (;;) {
450 if (p == top)
451 return (ret);
452 if (p->p_sibling.le_next) {
453 p = p->p_sibling.le_next;
454 break;
455 }
456 p = p->p_pptr;
457 }
458 }
459 /*NOTREACHED*/
460 }
461
462 int
ktrwrite(p,kth)463 ktrwrite(p, kth)
464 struct proc *p;
465 struct ktr_header *kth;
466 {
467 struct uio auio;
468 struct iovec aiov[2];
469 int error;
470 struct vnode *vp = p->p_tracep;
471
472 if (vp == NULL)
473 return 0;
474 auio.uio_iov = &aiov[0];
475 auio.uio_offset = 0;
476 auio.uio_segflg = UIO_SYSSPACE;
477 auio.uio_rw = UIO_WRITE;
478 aiov[0].iov_base = (caddr_t)kth;
479 aiov[0].iov_len = sizeof(struct ktr_header);
480 auio.uio_resid = sizeof(struct ktr_header);
481 auio.uio_iovcnt = 1;
482 auio.uio_procp = (struct proc *)0;
483 if (kth->ktr_len > 0) {
484 auio.uio_iovcnt++;
485 aiov[1].iov_base = kth->ktr_buf;
486 aiov[1].iov_len = kth->ktr_len;
487 auio.uio_resid += kth->ktr_len;
488 }
489 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
490 error = VOP_WRITE(vp, &auio, IO_UNIT|IO_APPEND, p->p_ucred);
491 VOP_UNLOCK(vp, 0, p);
492 if (!error)
493 return 0;
494 /*
495 * If error encountered, give up tracing on this vnode.
496 */
497 log(LOG_NOTICE, "ktrace write failed, errno %d, tracing stopped\n",
498 error);
499 for (p = LIST_FIRST(&allproc); p != NULL; p = LIST_NEXT(p, p_list)) {
500 if (p->p_tracep == vp) {
501 p->p_traceflag = 0;
502 ktrsettracevnode(p, NULL);
503 }
504 }
505
506 return error;
507 }
508
509 /*
510 * Return true if caller has permission to set the ktracing state
511 * of target. Essentially, the target can't possess any
512 * more permissions than the caller. KTRFAC_ROOT signifies that
513 * root previously set the tracing status on the target process, and
514 * so, only root may further change it.
515 *
516 * TODO: check groups. use caller effective gid.
517 */
518 int
ktrcanset(callp,targetp)519 ktrcanset(callp, targetp)
520 struct proc *callp, *targetp;
521 {
522 struct pcred *caller = callp->p_cred;
523 struct pcred *target = targetp->p_cred;
524
525 if ((caller->pc_ucred->cr_uid == target->p_ruid &&
526 target->p_ruid == target->p_svuid &&
527 caller->p_rgid == target->p_rgid && /* XXX */
528 target->p_rgid == target->p_svgid &&
529 (targetp->p_traceflag & KTRFAC_ROOT) == 0 &&
530 !ISSET(targetp->p_flag, P_SUGID)) ||
531 caller->pc_ucred->cr_uid == 0)
532 return (1);
533
534 return (0);
535 }
536
537 #endif
538