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