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