filemon_ktrace.c revision 1.2 1 1.2 riastrad /* $NetBSD: filemon_ktrace.c,v 1.2 2020/01/19 20:22:57 riastradh Exp $ */
2 1.1 riastrad
3 1.1 riastrad /*-
4 1.1 riastrad * Copyright (c) 2019 The NetBSD Foundation, Inc.
5 1.1 riastrad * All rights reserved.
6 1.1 riastrad *
7 1.1 riastrad * This code is derived from software contributed to The NetBSD Foundation
8 1.1 riastrad * by Taylor R. Campbell.
9 1.1 riastrad *
10 1.1 riastrad * Redistribution and use in source and binary forms, with or without
11 1.1 riastrad * modification, are permitted provided that the following conditions
12 1.1 riastrad * are met:
13 1.1 riastrad * 1. Redistributions of source code must retain the above copyright
14 1.1 riastrad * notice, this list of conditions and the following disclaimer.
15 1.1 riastrad * 2. Redistributions in binary form must reproduce the above copyright
16 1.1 riastrad * notice, this list of conditions and the following disclaimer in the
17 1.1 riastrad * documentation and/or other materials provided with the distribution.
18 1.1 riastrad *
19 1.1 riastrad * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 1.1 riastrad * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 1.1 riastrad * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 1.1 riastrad * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 1.1 riastrad * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 1.1 riastrad * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 1.1 riastrad * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 1.1 riastrad * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 1.1 riastrad * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 1.1 riastrad * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 1.1 riastrad * POSSIBILITY OF SUCH DAMAGE.
30 1.1 riastrad */
31 1.1 riastrad
32 1.2 riastrad #define _KERNTYPES /* register_t */
33 1.2 riastrad
34 1.1 riastrad #include "filemon.h"
35 1.1 riastrad
36 1.1 riastrad #include <sys/param.h>
37 1.1 riastrad #include <sys/types.h>
38 1.1 riastrad #include <sys/rbtree.h>
39 1.1 riastrad #include <sys/syscall.h>
40 1.1 riastrad #include <sys/time.h>
41 1.1 riastrad #include <sys/uio.h>
42 1.1 riastrad #include <sys/wait.h>
43 1.1 riastrad
44 1.1 riastrad #include <sys/ktrace.h>
45 1.1 riastrad
46 1.1 riastrad #include <assert.h>
47 1.1 riastrad #include <err.h>
48 1.1 riastrad #include <errno.h>
49 1.1 riastrad #include <fcntl.h>
50 1.1 riastrad #include <stdbool.h>
51 1.1 riastrad #include <stddef.h>
52 1.1 riastrad #include <stdio.h>
53 1.1 riastrad #include <stdlib.h>
54 1.1 riastrad #include <string.h>
55 1.1 riastrad #include <unistd.h>
56 1.1 riastrad
57 1.1 riastrad #ifndef AT_CWD
58 1.1 riastrad #define AT_CWD -1
59 1.1 riastrad #endif
60 1.1 riastrad
61 1.1 riastrad struct filemon;
62 1.1 riastrad struct filemon_key;
63 1.1 riastrad struct filemon_state;
64 1.1 riastrad
65 1.1 riastrad typedef struct filemon_state *filemon_syscall_t(struct filemon *,
66 1.1 riastrad const struct filemon_key *, const struct ktr_syscall *);
67 1.1 riastrad
68 1.1 riastrad static filemon_syscall_t filemon_sys_chdir;
69 1.1 riastrad static filemon_syscall_t filemon_sys_execve;
70 1.1 riastrad static filemon_syscall_t filemon_sys_exit;
71 1.1 riastrad static filemon_syscall_t filemon_sys_fork;
72 1.1 riastrad static filemon_syscall_t filemon_sys_link;
73 1.1 riastrad static filemon_syscall_t filemon_sys_open;
74 1.1 riastrad static filemon_syscall_t filemon_sys_openat;
75 1.1 riastrad static filemon_syscall_t filemon_sys_symlink;
76 1.1 riastrad static filemon_syscall_t filemon_sys_unlink;
77 1.1 riastrad static filemon_syscall_t filemon_sys_rename;
78 1.1 riastrad
79 1.1 riastrad static filemon_syscall_t *const filemon_syscalls[] = {
80 1.1 riastrad [SYS_chdir] = &filemon_sys_chdir,
81 1.1 riastrad [SYS_execve] = &filemon_sys_execve,
82 1.1 riastrad [SYS_exit] = &filemon_sys_exit,
83 1.1 riastrad [SYS_fork] = &filemon_sys_fork,
84 1.1 riastrad [SYS_link] = &filemon_sys_link,
85 1.1 riastrad [SYS_open] = &filemon_sys_open,
86 1.1 riastrad [SYS_openat] = &filemon_sys_openat,
87 1.1 riastrad [SYS_symlink] = &filemon_sys_symlink,
88 1.1 riastrad [SYS_unlink] = &filemon_sys_unlink,
89 1.1 riastrad [SYS_rename] = &filemon_sys_rename,
90 1.1 riastrad };
91 1.1 riastrad
92 1.1 riastrad struct filemon {
93 1.1 riastrad int ktrfd; /* kernel writes ktrace events here */
94 1.1 riastrad FILE *in; /* we read ktrace events from here */
95 1.1 riastrad FILE *out; /* we write filemon events to here */
96 1.1 riastrad rb_tree_t active;
97 1.1 riastrad pid_t child;
98 1.1 riastrad
99 1.1 riastrad /* I/O state machine. */
100 1.1 riastrad enum {
101 1.1 riastrad FILEMON_START = 0,
102 1.1 riastrad FILEMON_HEADER,
103 1.1 riastrad FILEMON_PAYLOAD,
104 1.1 riastrad FILEMON_ERROR,
105 1.1 riastrad } state;
106 1.1 riastrad unsigned char *p;
107 1.1 riastrad size_t resid;
108 1.1 riastrad
109 1.1 riastrad /* I/O buffer. */
110 1.1 riastrad struct ktr_header hdr;
111 1.1 riastrad union {
112 1.1 riastrad struct ktr_syscall syscall;
113 1.1 riastrad struct ktr_sysret sysret;
114 1.1 riastrad char namei[PATH_MAX];
115 1.1 riastrad unsigned char buf[4096];
116 1.1 riastrad } payload;
117 1.1 riastrad };
118 1.1 riastrad
119 1.1 riastrad struct filemon_state {
120 1.1 riastrad struct filemon_key {
121 1.1 riastrad pid_t pid;
122 1.1 riastrad lwpid_t lid;
123 1.1 riastrad } key;
124 1.1 riastrad struct rb_node node;
125 1.1 riastrad int syscode;
126 1.1 riastrad void (*show)(struct filemon *, const struct filemon_state *,
127 1.1 riastrad const struct ktr_sysret *);
128 1.1 riastrad unsigned i;
129 1.1 riastrad unsigned npath;
130 1.1 riastrad char *path[/*npath*/];
131 1.1 riastrad };
132 1.1 riastrad
133 1.1 riastrad static int
134 1.1 riastrad compare_filemon_states(void *cookie, const void *na, const void *nb)
135 1.1 riastrad {
136 1.1 riastrad const struct filemon_state *Sa = na;
137 1.1 riastrad const struct filemon_state *Sb = nb;
138 1.1 riastrad
139 1.1 riastrad if (Sa->key.pid < Sb->key.pid)
140 1.1 riastrad return -1;
141 1.1 riastrad if (Sa->key.pid > Sb->key.pid)
142 1.1 riastrad return +1;
143 1.1 riastrad if (Sa->key.lid < Sb->key.lid)
144 1.1 riastrad return -1;
145 1.1 riastrad if (Sa->key.lid > Sb->key.lid)
146 1.1 riastrad return +1;
147 1.1 riastrad return 0;
148 1.1 riastrad }
149 1.1 riastrad
150 1.1 riastrad static int
151 1.1 riastrad compare_filemon_key(void *cookie, const void *n, const void *k)
152 1.1 riastrad {
153 1.1 riastrad const struct filemon_state *S = n;
154 1.1 riastrad const struct filemon_key *key = k;
155 1.1 riastrad
156 1.1 riastrad if (S->key.pid < key->pid)
157 1.1 riastrad return -1;
158 1.1 riastrad if (S->key.pid > key->pid)
159 1.1 riastrad return +1;
160 1.1 riastrad if (S->key.lid < key->lid)
161 1.1 riastrad return -1;
162 1.1 riastrad if (S->key.lid > key->lid)
163 1.1 riastrad return +1;
164 1.1 riastrad return 0;
165 1.1 riastrad }
166 1.1 riastrad
167 1.1 riastrad static const rb_tree_ops_t filemon_rb_ops = {
168 1.1 riastrad .rbto_compare_nodes = &compare_filemon_states,
169 1.1 riastrad .rbto_compare_key = &compare_filemon_key,
170 1.1 riastrad .rbto_node_offset = offsetof(struct filemon_state, node),
171 1.1 riastrad .rbto_context = NULL,
172 1.1 riastrad };
173 1.1 riastrad
174 1.1 riastrad /*
175 1.1 riastrad * filemon_path()
176 1.1 riastrad *
177 1.1 riastrad * Return a pointer to a constant string denoting the `path' of
178 1.1 riastrad * the filemon.
179 1.1 riastrad */
180 1.1 riastrad const char *
181 1.1 riastrad filemon_path(void)
182 1.1 riastrad {
183 1.1 riastrad
184 1.1 riastrad return "ktrace";
185 1.1 riastrad }
186 1.1 riastrad
187 1.1 riastrad /*
188 1.1 riastrad * filemon_open()
189 1.1 riastrad *
190 1.1 riastrad * Allocate a filemon descriptor. Returns NULL and sets errno on
191 1.1 riastrad * failure.
192 1.1 riastrad */
193 1.1 riastrad struct filemon *
194 1.1 riastrad filemon_open(void)
195 1.1 riastrad {
196 1.1 riastrad struct filemon *F;
197 1.1 riastrad int ktrpipe[2];
198 1.1 riastrad int error;
199 1.1 riastrad
200 1.1 riastrad /* Allocate and zero a struct filemon object. */
201 1.1 riastrad F = calloc(1, sizeof(*F));
202 1.1 riastrad if (F == NULL)
203 1.1 riastrad return NULL;
204 1.1 riastrad
205 1.1 riastrad /* Create a pipe for ktrace events. */
206 1.1 riastrad if (pipe2(ktrpipe, O_CLOEXEC|O_NONBLOCK) == -1) {
207 1.1 riastrad error = errno;
208 1.1 riastrad goto fail0;
209 1.1 riastrad }
210 1.1 riastrad
211 1.1 riastrad /* Create a file stream for reading the ktrace events. */
212 1.1 riastrad if ((F->in = fdopen(ktrpipe[0], "r")) == NULL) {
213 1.1 riastrad error = errno;
214 1.1 riastrad goto fail1;
215 1.1 riastrad }
216 1.1 riastrad ktrpipe[0] = -1; /* claimed by fdopen */
217 1.1 riastrad
218 1.1 riastrad /*
219 1.1 riastrad * Set the fd for writing ktrace events and initialize the
220 1.1 riastrad * rbtree. The rest can be safely initialized to zero.
221 1.1 riastrad */
222 1.1 riastrad F->ktrfd = ktrpipe[1];
223 1.1 riastrad rb_tree_init(&F->active, &filemon_rb_ops);
224 1.1 riastrad
225 1.1 riastrad /* Success! */
226 1.1 riastrad return F;
227 1.1 riastrad
228 1.1 riastrad fail2: __unused
229 1.1 riastrad (void)fclose(F->in);
230 1.1 riastrad fail1: (void)close(ktrpipe[0]);
231 1.1 riastrad (void)close(ktrpipe[1]);
232 1.1 riastrad fail0: free(F);
233 1.1 riastrad errno = error;
234 1.1 riastrad return NULL;
235 1.1 riastrad }
236 1.1 riastrad
237 1.1 riastrad /*
238 1.1 riastrad * filemon_closefd(F)
239 1.1 riastrad *
240 1.1 riastrad * Internal subroutine to try to flush and close the output file.
241 1.1 riastrad * If F is not open for output, do nothing. Never leaves F open
242 1.1 riastrad * for output even on failure. Returns 0 on success; sets errno
243 1.1 riastrad * and return -1 on failure.
244 1.1 riastrad */
245 1.1 riastrad static int
246 1.1 riastrad filemon_closefd(struct filemon *F)
247 1.1 riastrad {
248 1.1 riastrad int error = 0;
249 1.1 riastrad
250 1.1 riastrad /* If we're not open, nothing to do. */
251 1.1 riastrad if (F->out == NULL)
252 1.1 riastrad return 0;
253 1.1 riastrad
254 1.1 riastrad /*
255 1.1 riastrad * Flush it, close it, and null it unconditionally, but be
256 1.1 riastrad * careful to return the earliest error in errno.
257 1.1 riastrad */
258 1.1 riastrad if (fflush(F->out) == EOF && error == 0)
259 1.1 riastrad error = errno;
260 1.1 riastrad if (fclose(F->out) == EOF && error == 0)
261 1.1 riastrad error = errno;
262 1.1 riastrad F->out = NULL;
263 1.1 riastrad
264 1.1 riastrad /* Set errno and return -1 if anything went wrong. */
265 1.1 riastrad if (error) {
266 1.1 riastrad errno = error;
267 1.1 riastrad return -1;
268 1.1 riastrad }
269 1.1 riastrad
270 1.1 riastrad /* Success! */
271 1.1 riastrad return 0;
272 1.1 riastrad }
273 1.1 riastrad
274 1.1 riastrad /*
275 1.1 riastrad * filemon_setfd(F, fd)
276 1.1 riastrad *
277 1.1 riastrad * Cause filemon activity on F to be sent to fd. Claims ownership
278 1.1 riastrad * of fd; caller should not use fd afterward, and any duplicates
279 1.1 riastrad * of fd may see their file positions changed.
280 1.1 riastrad */
281 1.1 riastrad int
282 1.1 riastrad filemon_setfd(struct filemon *F, int fd)
283 1.1 riastrad {
284 1.1 riastrad
285 1.1 riastrad /*
286 1.1 riastrad * Close an existing output file if done. Fail now if there's
287 1.1 riastrad * an error closing.
288 1.1 riastrad */
289 1.1 riastrad if ((filemon_closefd(F)) == -1)
290 1.1 riastrad return -1;
291 1.1 riastrad assert(F->out == NULL);
292 1.1 riastrad
293 1.1 riastrad /* Open a file stream and claim ownership of the fd. */
294 1.1 riastrad if ((F->out = fdopen(fd, "a")) == NULL)
295 1.1 riastrad return -1;
296 1.1 riastrad
297 1.1 riastrad /*
298 1.1 riastrad * Print the opening output. Any failure will be deferred
299 1.1 riastrad * until closing. For hysterical raisins, we show the parent
300 1.1 riastrad * pid, not the child pid.
301 1.1 riastrad */
302 1.1 riastrad fprintf(F->out, "# filemon version 4\n");
303 1.1 riastrad fprintf(F->out, "# Target pid %jd\n", (intmax_t)getpid());
304 1.1 riastrad fprintf(F->out, "V 4\n");
305 1.1 riastrad
306 1.1 riastrad /* Success! */
307 1.1 riastrad return 0;
308 1.1 riastrad }
309 1.1 riastrad
310 1.1 riastrad /*
311 1.1 riastrad * filemon_setpid_parent(F, pid)
312 1.1 riastrad *
313 1.1 riastrad * Set the traced pid, from the parent. Never fails.
314 1.1 riastrad */
315 1.1 riastrad void
316 1.1 riastrad filemon_setpid_parent(struct filemon *F, pid_t pid)
317 1.1 riastrad {
318 1.1 riastrad
319 1.1 riastrad F->child = pid;
320 1.1 riastrad }
321 1.1 riastrad
322 1.1 riastrad /*
323 1.1 riastrad * filemon_setpid_child(F, pid)
324 1.1 riastrad *
325 1.1 riastrad * Set the traced pid, from the child. Returns 0 on success; sets
326 1.1 riastrad * errno and returns -1 on failure.
327 1.1 riastrad */
328 1.1 riastrad int
329 1.1 riastrad filemon_setpid_child(const struct filemon *F, pid_t pid)
330 1.1 riastrad {
331 1.1 riastrad int ops, trpoints;
332 1.1 riastrad
333 1.1 riastrad ops = KTROP_SET|KTRFLAG_DESCEND;
334 1.1 riastrad trpoints = KTRFACv2;
335 1.1 riastrad trpoints |= KTRFAC_SYSCALL|KTRFAC_NAMEI|KTRFAC_SYSRET;
336 1.1 riastrad trpoints |= KTRFAC_INHERIT;
337 1.1 riastrad if (fktrace(F->ktrfd, ops, trpoints, pid) == -1)
338 1.1 riastrad return -1;
339 1.1 riastrad
340 1.1 riastrad return 0;
341 1.1 riastrad }
342 1.1 riastrad
343 1.1 riastrad /*
344 1.1 riastrad * filemon_close(F)
345 1.1 riastrad *
346 1.1 riastrad * Close F for output if necessary, and free a filemon descriptor.
347 1.1 riastrad * Returns 0 on success; sets errno and returns -1 on failure, but
348 1.1 riastrad * frees the filemon descriptor either way;
349 1.1 riastrad */
350 1.1 riastrad int
351 1.1 riastrad filemon_close(struct filemon *F)
352 1.1 riastrad {
353 1.1 riastrad struct filemon_state *S;
354 1.1 riastrad int error = 0;
355 1.1 riastrad
356 1.1 riastrad /* Close for output. */
357 1.1 riastrad if (filemon_closefd(F) == -1 && error == 0)
358 1.1 riastrad error = errno;
359 1.1 riastrad
360 1.1 riastrad /* Close the ktrace pipe. */
361 1.1 riastrad if (fclose(F->in) == EOF && error == 0)
362 1.1 riastrad error = errno;
363 1.1 riastrad if (close(F->ktrfd) == -1 && error == 0)
364 1.1 riastrad error = errno;
365 1.1 riastrad
366 1.1 riastrad /* Free any active records. */
367 1.1 riastrad while ((S = RB_TREE_MIN(&F->active)) != NULL) {
368 1.1 riastrad rb_tree_remove_node(&F->active, S);
369 1.1 riastrad free(S);
370 1.1 riastrad }
371 1.1 riastrad
372 1.1 riastrad /* Free the filemon descriptor. */
373 1.1 riastrad free(F);
374 1.1 riastrad
375 1.1 riastrad /* Set errno and return -1 if anything went wrong. */
376 1.1 riastrad if (error) {
377 1.1 riastrad errno = error;
378 1.1 riastrad return -1;
379 1.1 riastrad }
380 1.1 riastrad
381 1.1 riastrad /* Success! */
382 1.1 riastrad return 0;
383 1.1 riastrad }
384 1.1 riastrad
385 1.1 riastrad /*
386 1.1 riastrad * filemon_readfd(F)
387 1.1 riastrad *
388 1.1 riastrad * Returns a file descriptor which will select/poll ready for read
389 1.1 riastrad * when there are filemon events to be processed by
390 1.1 riastrad * filemon_process, or -1 if anything has gone wrong.
391 1.1 riastrad */
392 1.1 riastrad int
393 1.1 riastrad filemon_readfd(const struct filemon *F)
394 1.1 riastrad {
395 1.1 riastrad
396 1.1 riastrad if (F->state == FILEMON_ERROR)
397 1.1 riastrad return -1;
398 1.1 riastrad return fileno(F->in);
399 1.1 riastrad }
400 1.1 riastrad
401 1.1 riastrad /*
402 1.1 riastrad * filemon_dispatch(F)
403 1.1 riastrad *
404 1.1 riastrad * Internal subroutine to dispatch a filemon ktrace event.
405 1.1 riastrad * Silently ignore events that we don't recognize.
406 1.1 riastrad */
407 1.1 riastrad static void
408 1.1 riastrad filemon_dispatch(struct filemon *F)
409 1.1 riastrad {
410 1.1 riastrad const struct filemon_key key = {
411 1.1 riastrad .pid = F->hdr.ktr_pid,
412 1.1 riastrad .lid = F->hdr.ktr_lid,
413 1.1 riastrad };
414 1.1 riastrad struct filemon_state *S;
415 1.1 riastrad
416 1.1 riastrad switch (F->hdr.ktr_type) {
417 1.1 riastrad case KTR_SYSCALL: {
418 1.1 riastrad struct ktr_syscall *call = &F->payload.syscall;
419 1.1 riastrad struct filemon_state *S1;
420 1.1 riastrad
421 1.1 riastrad /* Validate the syscall code. */
422 1.1 riastrad if (call->ktr_code < 0 ||
423 1.1 riastrad (size_t)call->ktr_code >= __arraycount(filemon_syscalls) ||
424 1.1 riastrad filemon_syscalls[call->ktr_code] == NULL)
425 1.1 riastrad break;
426 1.1 riastrad
427 1.1 riastrad /*
428 1.1 riastrad * Invoke the syscall-specific logic to create a new
429 1.1 riastrad * active state.
430 1.1 riastrad */
431 1.1 riastrad S = (*filemon_syscalls[call->ktr_code])(F, &key, call);
432 1.1 riastrad if (S == NULL)
433 1.1 riastrad break;
434 1.1 riastrad
435 1.1 riastrad /*
436 1.1 riastrad * Insert the active state, or ignore it if there
437 1.1 riastrad * already is one.
438 1.1 riastrad *
439 1.1 riastrad * Collisions shouldn't happen because the states are
440 1.1 riastrad * keyed by <pid,lid>, in which syscalls should happen
441 1.1 riastrad * sequentially in CALL/RET pairs, but let's be
442 1.1 riastrad * defensive.
443 1.1 riastrad */
444 1.1 riastrad S1 = rb_tree_insert_node(&F->active, S);
445 1.1 riastrad if (S1 != S) {
446 1.1 riastrad /* XXX Which one to drop? */
447 1.1 riastrad free(S);
448 1.1 riastrad break;
449 1.1 riastrad }
450 1.1 riastrad break;
451 1.1 riastrad }
452 1.1 riastrad case KTR_NAMEI:
453 1.1 riastrad /* Find an active syscall state, or drop it. */
454 1.1 riastrad S = rb_tree_find_node(&F->active, &key);
455 1.1 riastrad if (S == NULL)
456 1.1 riastrad break;
457 1.1 riastrad /* Find the position of the next path, or drop it. */
458 1.1 riastrad if (S->i >= S->npath)
459 1.1 riastrad break;
460 1.1 riastrad /* Record the path. */
461 1.1 riastrad S->path[S->i++] = strndup(F->payload.namei,
462 1.1 riastrad sizeof F->payload.namei);
463 1.1 riastrad break;
464 1.1 riastrad case KTR_SYSRET: {
465 1.1 riastrad struct ktr_sysret *ret = &F->payload.sysret;
466 1.1 riastrad unsigned i;
467 1.1 riastrad
468 1.1 riastrad /* Find and remove an active syscall state, or drop it. */
469 1.1 riastrad S = rb_tree_find_node(&F->active, &key);
470 1.1 riastrad if (S == NULL)
471 1.1 riastrad break;
472 1.1 riastrad rb_tree_remove_node(&F->active, S);
473 1.1 riastrad
474 1.1 riastrad /*
475 1.1 riastrad * If the active syscall state matches this return,
476 1.1 riastrad * invoke the syscall-specific logic to show a filemon
477 1.1 riastrad * event.
478 1.1 riastrad */
479 1.1 riastrad /* XXX What to do if syscall code doesn't match? */
480 1.1 riastrad if (S->i == S->npath && S->syscode == ret->ktr_code)
481 1.1 riastrad (*S->show)(F, S, ret);
482 1.1 riastrad
483 1.1 riastrad /* Free the state now that it is no longer active. */
484 1.1 riastrad for (i = 0; i < S->i; i++)
485 1.1 riastrad free(S->path[i]);
486 1.1 riastrad free(S);
487 1.1 riastrad break;
488 1.1 riastrad }
489 1.1 riastrad default:
490 1.1 riastrad /* Ignore all other ktrace events. */
491 1.1 riastrad break;
492 1.1 riastrad }
493 1.1 riastrad }
494 1.1 riastrad
495 1.1 riastrad /*
496 1.1 riastrad * filemon_process(F)
497 1.1 riastrad *
498 1.1 riastrad * Process all pending events after filemon_readfd(F) has
499 1.1 riastrad * selected/polled ready for read.
500 1.1 riastrad *
501 1.1 riastrad * Returns -1 on failure, 0 on end of events, and anything else if
502 1.1 riastrad * there may be more events.
503 1.1 riastrad *
504 1.1 riastrad * XXX What about fairness to other activities in the event loop?
505 1.1 riastrad * If we stop while there's events buffered in F->in, then select
506 1.1 riastrad * or poll may not return ready even though there's work queued up
507 1.1 riastrad * in the buffer of F->in, but if we don't stop then ktrace events
508 1.1 riastrad * may overwhelm all other activity in the event loop.
509 1.1 riastrad */
510 1.1 riastrad int
511 1.1 riastrad filemon_process(struct filemon *F)
512 1.1 riastrad {
513 1.1 riastrad size_t nread;
514 1.1 riastrad
515 1.1 riastrad top: /* If the child has exited, nothing to do. */
516 1.1 riastrad /* XXX What if one thread calls exit while another is running? */
517 1.1 riastrad if (F->child == 0)
518 1.1 riastrad return 0;
519 1.1 riastrad
520 1.1 riastrad /* If we're waiting for input, read some. */
521 1.1 riastrad if (F->resid) {
522 1.1 riastrad nread = fread(F->p, 1, F->resid, F->in);
523 1.1 riastrad if (nread == 0) {
524 1.1 riastrad if (feof(F->in))
525 1.1 riastrad return 0;
526 1.1 riastrad assert(ferror(F->in));
527 1.1 riastrad /*
528 1.1 riastrad * If interrupted or would block, there may be
529 1.1 riastrad * more events. Otherwise fail.
530 1.1 riastrad */
531 1.1 riastrad if (errno == EAGAIN || errno == EINTR)
532 1.1 riastrad return 1;
533 1.1 riastrad F->state = FILEMON_ERROR;
534 1.1 riastrad F->p = NULL;
535 1.1 riastrad F->resid = 0;
536 1.1 riastrad return -1;
537 1.1 riastrad }
538 1.1 riastrad assert(nread <= F->resid);
539 1.1 riastrad F->p += nread;
540 1.1 riastrad F->resid -= nread;
541 1.1 riastrad if (F->resid) /* may be more events */
542 1.1 riastrad return 1;
543 1.1 riastrad }
544 1.1 riastrad
545 1.1 riastrad /* Process a state transition now that we've read a buffer. */
546 1.1 riastrad switch (F->state) {
547 1.1 riastrad case FILEMON_START: /* just started filemon; read header next */
548 1.1 riastrad F->state = FILEMON_HEADER;
549 1.1 riastrad F->p = (void *)&F->hdr;
550 1.1 riastrad F->resid = sizeof F->hdr;
551 1.1 riastrad goto top;
552 1.1 riastrad case FILEMON_HEADER: /* read header */
553 1.1 riastrad /* Sanity-check ktrace header; then read payload. */
554 1.1 riastrad if (F->hdr.ktr_len < 0 ||
555 1.1 riastrad (size_t)F->hdr.ktr_len > sizeof F->payload) {
556 1.1 riastrad F->state = FILEMON_ERROR;
557 1.1 riastrad F->p = NULL;
558 1.1 riastrad F->resid = 0;
559 1.1 riastrad errno = EIO;
560 1.1 riastrad return -1;
561 1.1 riastrad }
562 1.1 riastrad F->state = FILEMON_PAYLOAD;
563 1.1 riastrad F->p = (void *)&F->payload;
564 1.1 riastrad F->resid = (size_t)F->hdr.ktr_len;
565 1.1 riastrad goto top;
566 1.1 riastrad case FILEMON_PAYLOAD: /* read header and payload */
567 1.1 riastrad /* Dispatch ktrace event; then read next header. */
568 1.1 riastrad filemon_dispatch(F);
569 1.1 riastrad F->state = FILEMON_HEADER;
570 1.1 riastrad F->p = (void *)&F->hdr;
571 1.1 riastrad F->resid = sizeof F->hdr;
572 1.1 riastrad goto top;
573 1.1 riastrad default: /* paranoia */
574 1.1 riastrad F->state = FILEMON_ERROR;
575 1.1 riastrad /*FALLTHROUGH*/
576 1.1 riastrad case FILEMON_ERROR: /* persistent error indicator */
577 1.1 riastrad F->p = NULL;
578 1.1 riastrad F->resid = 0;
579 1.1 riastrad errno = EIO;
580 1.1 riastrad return -1;
581 1.1 riastrad }
582 1.1 riastrad }
583 1.1 riastrad
584 1.1 riastrad static struct filemon_state *
585 1.1 riastrad syscall_enter(struct filemon *F,
586 1.1 riastrad const struct filemon_key *key, const struct ktr_syscall *call,
587 1.1 riastrad unsigned npath,
588 1.1 riastrad void (*show)(struct filemon *, const struct filemon_state *,
589 1.1 riastrad const struct ktr_sysret *))
590 1.1 riastrad {
591 1.1 riastrad struct filemon_state *S;
592 1.1 riastrad unsigned i;
593 1.1 riastrad
594 1.1 riastrad S = calloc(1, offsetof(struct filemon_state, path[npath]));
595 1.1 riastrad if (S == NULL)
596 1.1 riastrad return NULL;
597 1.1 riastrad S->key = *key;
598 1.1 riastrad S->show = show;
599 1.1 riastrad S->syscode = call->ktr_code;
600 1.1 riastrad S->i = 0;
601 1.1 riastrad S->npath = npath;
602 1.1 riastrad for (i = 0; i < npath; i++)
603 1.1 riastrad S->path[i] = NULL; /* paranoia */
604 1.1 riastrad
605 1.1 riastrad return S;
606 1.1 riastrad }
607 1.1 riastrad
608 1.1 riastrad static void
609 1.1 riastrad show_paths(struct filemon *F, const struct filemon_state *S,
610 1.1 riastrad const struct ktr_sysret *ret, const char *prefix)
611 1.1 riastrad {
612 1.1 riastrad unsigned i;
613 1.1 riastrad
614 1.1 riastrad /* Caller must ensure all paths have been specified. */
615 1.1 riastrad assert(S->i == S->npath);
616 1.1 riastrad
617 1.1 riastrad /*
618 1.1 riastrad * Ignore it if it failed or yielded EJUSTRETURN (-2), or if
619 1.1 riastrad * we're not producing output.
620 1.1 riastrad */
621 1.1 riastrad if (ret->ktr_error && ret->ktr_error != -2)
622 1.1 riastrad return;
623 1.1 riastrad if (F->out == NULL)
624 1.1 riastrad return;
625 1.1 riastrad
626 1.1 riastrad /*
627 1.1 riastrad * Print the prefix, pid, and paths -- with the paths quoted if
628 1.1 riastrad * there's more than one.
629 1.1 riastrad */
630 1.1 riastrad fprintf(F->out, "%s %jd", prefix, (intmax_t)S->key.pid);
631 1.1 riastrad for (i = 0; i < S->npath; i++) {
632 1.1 riastrad const char *q = S->npath > 1 ? "'" : "";
633 1.1 riastrad fprintf(F->out, " %s%s%s", q, S->path[i], q);
634 1.1 riastrad }
635 1.1 riastrad fprintf(F->out, "\n");
636 1.1 riastrad }
637 1.1 riastrad
638 1.1 riastrad static void
639 1.1 riastrad show_retval(struct filemon *F, const struct filemon_state *S,
640 1.1 riastrad const struct ktr_sysret *ret, const char *prefix)
641 1.1 riastrad {
642 1.1 riastrad
643 1.1 riastrad /*
644 1.1 riastrad * Ignore it if it failed or yielded EJUSTRETURN (-2), or if
645 1.1 riastrad * we're not producing output.
646 1.1 riastrad */
647 1.1 riastrad if (ret->ktr_error && ret->ktr_error != -2)
648 1.1 riastrad return;
649 1.1 riastrad if (F->out == NULL)
650 1.1 riastrad return;
651 1.1 riastrad
652 1.1 riastrad fprintf(F->out, "%s %jd %jd\n", prefix, (intmax_t)S->key.pid,
653 1.1 riastrad (intmax_t)ret->ktr_retval);
654 1.1 riastrad }
655 1.1 riastrad
656 1.1 riastrad static void
657 1.1 riastrad show_chdir(struct filemon *F, const struct filemon_state *S,
658 1.1 riastrad const struct ktr_sysret *ret)
659 1.1 riastrad {
660 1.1 riastrad show_paths(F, S, ret, "C");
661 1.1 riastrad }
662 1.1 riastrad
663 1.1 riastrad static void
664 1.1 riastrad show_execve(struct filemon *F, const struct filemon_state *S,
665 1.1 riastrad const struct ktr_sysret *ret)
666 1.1 riastrad {
667 1.1 riastrad return show_paths(F, S, ret, "E");
668 1.1 riastrad }
669 1.1 riastrad
670 1.1 riastrad static void
671 1.1 riastrad show_fork(struct filemon *F, const struct filemon_state *S,
672 1.1 riastrad const struct ktr_sysret *ret)
673 1.1 riastrad {
674 1.1 riastrad show_retval(F, S, ret, "F");
675 1.1 riastrad }
676 1.1 riastrad
677 1.1 riastrad static void
678 1.1 riastrad show_link(struct filemon *F, const struct filemon_state *S,
679 1.1 riastrad const struct ktr_sysret *ret)
680 1.1 riastrad {
681 1.1 riastrad show_paths(F, S, ret, "L"); /* XXX same as symlink */
682 1.1 riastrad }
683 1.1 riastrad
684 1.1 riastrad static void
685 1.1 riastrad show_open_read(struct filemon *F, const struct filemon_state *S,
686 1.1 riastrad const struct ktr_sysret *ret)
687 1.1 riastrad {
688 1.1 riastrad show_paths(F, S, ret, "R");
689 1.1 riastrad }
690 1.1 riastrad
691 1.1 riastrad static void
692 1.1 riastrad show_open_write(struct filemon *F, const struct filemon_state *S,
693 1.1 riastrad const struct ktr_sysret *ret)
694 1.1 riastrad {
695 1.1 riastrad show_paths(F, S, ret, "W");
696 1.1 riastrad }
697 1.1 riastrad
698 1.1 riastrad static void
699 1.1 riastrad show_open_readwrite(struct filemon *F, const struct filemon_state *S,
700 1.1 riastrad const struct ktr_sysret *ret)
701 1.1 riastrad {
702 1.1 riastrad show_paths(F, S, ret, "R");
703 1.1 riastrad show_paths(F, S, ret, "W");
704 1.1 riastrad }
705 1.1 riastrad
706 1.1 riastrad static void
707 1.1 riastrad show_openat_read(struct filemon *F, const struct filemon_state *S,
708 1.1 riastrad const struct ktr_sysret *ret)
709 1.1 riastrad {
710 1.1 riastrad if (S->path[0][0] != '/')
711 1.1 riastrad show_paths(F, S, ret, "A");
712 1.1 riastrad show_paths(F, S, ret, "R");
713 1.1 riastrad }
714 1.1 riastrad
715 1.1 riastrad static void
716 1.1 riastrad show_openat_write(struct filemon *F, const struct filemon_state *S,
717 1.1 riastrad const struct ktr_sysret *ret)
718 1.1 riastrad {
719 1.1 riastrad if (S->path[0][0] != '/')
720 1.1 riastrad show_paths(F, S, ret, "A");
721 1.1 riastrad show_paths(F, S, ret, "W");
722 1.1 riastrad }
723 1.1 riastrad
724 1.1 riastrad static void
725 1.1 riastrad show_openat_readwrite(struct filemon *F, const struct filemon_state *S,
726 1.1 riastrad const struct ktr_sysret *ret)
727 1.1 riastrad {
728 1.1 riastrad if (S->path[0][0] != '/')
729 1.1 riastrad show_paths(F, S, ret, "A");
730 1.1 riastrad show_paths(F, S, ret, "R");
731 1.1 riastrad show_paths(F, S, ret, "W");
732 1.1 riastrad }
733 1.1 riastrad
734 1.1 riastrad static void
735 1.1 riastrad show_symlink(struct filemon *F, const struct filemon_state *S,
736 1.1 riastrad const struct ktr_sysret *ret)
737 1.1 riastrad {
738 1.1 riastrad show_paths(F, S, ret, "L"); /* XXX same as link */
739 1.1 riastrad }
740 1.1 riastrad
741 1.1 riastrad static void
742 1.1 riastrad show_unlink(struct filemon *F, const struct filemon_state *S,
743 1.1 riastrad const struct ktr_sysret *ret)
744 1.1 riastrad {
745 1.1 riastrad show_paths(F, S, ret, "D");
746 1.1 riastrad }
747 1.1 riastrad
748 1.1 riastrad static void
749 1.1 riastrad show_rename(struct filemon *F, const struct filemon_state *S,
750 1.1 riastrad const struct ktr_sysret *ret)
751 1.1 riastrad {
752 1.1 riastrad show_paths(F, S, ret, "M");
753 1.1 riastrad }
754 1.1 riastrad
755 1.1 riastrad static struct filemon_state *
756 1.1 riastrad filemon_sys_chdir(struct filemon *F, const struct filemon_key *key,
757 1.1 riastrad const struct ktr_syscall *call)
758 1.1 riastrad {
759 1.1 riastrad return syscall_enter(F, key, call, 1, &show_chdir);
760 1.1 riastrad }
761 1.1 riastrad
762 1.1 riastrad static struct filemon_state *
763 1.1 riastrad filemon_sys_execve(struct filemon *F, const struct filemon_key *key,
764 1.1 riastrad const struct ktr_syscall *call)
765 1.1 riastrad {
766 1.1 riastrad return syscall_enter(F, key, call, 1, &show_execve);
767 1.1 riastrad }
768 1.1 riastrad
769 1.1 riastrad static struct filemon_state *
770 1.1 riastrad filemon_sys_exit(struct filemon *F, const struct filemon_key *key,
771 1.1 riastrad const struct ktr_syscall *call)
772 1.1 riastrad {
773 1.1 riastrad const register_t *args = (const void *)&call[1];
774 1.1 riastrad int status = args[0];
775 1.1 riastrad
776 1.1 riastrad if (F->out) {
777 1.1 riastrad fprintf(F->out, "X %jd %d\n", (intmax_t)key->pid, status);
778 1.1 riastrad if (key->pid == F->child) {
779 1.1 riastrad fprintf(F->out, "# Bye bye\n");
780 1.1 riastrad F->child = 0;
781 1.1 riastrad }
782 1.1 riastrad }
783 1.1 riastrad return NULL;
784 1.1 riastrad }
785 1.1 riastrad
786 1.1 riastrad static struct filemon_state *
787 1.1 riastrad filemon_sys_fork(struct filemon *F, const struct filemon_key *key,
788 1.1 riastrad const struct ktr_syscall *call)
789 1.1 riastrad {
790 1.1 riastrad return syscall_enter(F, key, call, 0, &show_fork);
791 1.1 riastrad }
792 1.1 riastrad
793 1.1 riastrad static struct filemon_state *
794 1.1 riastrad filemon_sys_link(struct filemon *F, const struct filemon_key *key,
795 1.1 riastrad const struct ktr_syscall *call)
796 1.1 riastrad {
797 1.1 riastrad return syscall_enter(F, key, call, 2, &show_link);
798 1.1 riastrad }
799 1.1 riastrad
800 1.1 riastrad static struct filemon_state *
801 1.1 riastrad filemon_sys_open(struct filemon *F, const struct filemon_key *key,
802 1.1 riastrad const struct ktr_syscall *call)
803 1.1 riastrad {
804 1.1 riastrad const register_t *args = (const void *)&call[1];
805 1.1 riastrad int flags;
806 1.1 riastrad
807 1.1 riastrad if (call->ktr_argsize < 2)
808 1.1 riastrad return NULL;
809 1.1 riastrad flags = args[1];
810 1.1 riastrad
811 1.1 riastrad if ((flags & O_RDWR) == O_RDWR)
812 1.1 riastrad return syscall_enter(F, key, call, 1, &show_open_readwrite);
813 1.1 riastrad else if ((flags & O_WRONLY) == O_WRONLY)
814 1.1 riastrad return syscall_enter(F, key, call, 1, &show_open_write);
815 1.1 riastrad else if ((flags & O_RDONLY) == O_RDONLY)
816 1.1 riastrad return syscall_enter(F, key, call, 1, &show_open_read);
817 1.1 riastrad else
818 1.1 riastrad return NULL; /* XXX Do we care if no read or write? */
819 1.1 riastrad }
820 1.1 riastrad
821 1.1 riastrad static struct filemon_state *
822 1.1 riastrad filemon_sys_openat(struct filemon *F, const struct filemon_key *key,
823 1.1 riastrad const struct ktr_syscall *call)
824 1.1 riastrad {
825 1.1 riastrad const register_t *args = (const void *)&call[1];
826 1.1 riastrad int flags, fd;
827 1.1 riastrad
828 1.1 riastrad if (call->ktr_argsize < 3)
829 1.1 riastrad return NULL;
830 1.1 riastrad fd = args[0];
831 1.1 riastrad flags = args[2];
832 1.1 riastrad
833 1.1 riastrad if (fd == AT_CWD) {
834 1.1 riastrad if ((flags & O_RDWR) == O_RDWR)
835 1.1 riastrad return syscall_enter(F, key, call, 1,
836 1.1 riastrad &show_open_readwrite);
837 1.1 riastrad else if ((flags & O_WRONLY) == O_WRONLY)
838 1.1 riastrad return syscall_enter(F, key, call, 1,
839 1.1 riastrad &show_open_write);
840 1.1 riastrad else if ((flags & O_RDONLY) == O_RDONLY)
841 1.1 riastrad return syscall_enter(F, key, call, 1, &show_open_read);
842 1.1 riastrad else
843 1.1 riastrad return NULL;
844 1.1 riastrad } else {
845 1.1 riastrad if ((flags & O_RDWR) == O_RDWR)
846 1.1 riastrad return syscall_enter(F, key, call, 1,
847 1.1 riastrad &show_openat_readwrite);
848 1.1 riastrad else if ((flags & O_WRONLY) == O_WRONLY)
849 1.1 riastrad return syscall_enter(F, key, call, 1,
850 1.1 riastrad &show_openat_write);
851 1.1 riastrad else if ((flags & O_RDONLY) == O_RDONLY)
852 1.1 riastrad return syscall_enter(F, key, call, 1,
853 1.1 riastrad &show_openat_read);
854 1.1 riastrad else
855 1.1 riastrad return NULL;
856 1.1 riastrad }
857 1.1 riastrad }
858 1.1 riastrad
859 1.1 riastrad static struct filemon_state *
860 1.1 riastrad filemon_sys_symlink(struct filemon *F, const struct filemon_key *key,
861 1.1 riastrad const struct ktr_syscall *call)
862 1.1 riastrad {
863 1.1 riastrad return syscall_enter(F, key, call, 2, &show_symlink);
864 1.1 riastrad }
865 1.1 riastrad
866 1.1 riastrad static struct filemon_state *
867 1.1 riastrad filemon_sys_unlink(struct filemon *F, const struct filemon_key *key,
868 1.1 riastrad const struct ktr_syscall *call)
869 1.1 riastrad {
870 1.1 riastrad return syscall_enter(F, key, call, 1, &show_unlink);
871 1.1 riastrad }
872 1.1 riastrad
873 1.1 riastrad static struct filemon_state *
874 1.1 riastrad filemon_sys_rename(struct filemon *F, const struct filemon_key *key,
875 1.1 riastrad const struct ktr_syscall *call)
876 1.1 riastrad {
877 1.1 riastrad return syscall_enter(F, key, call, 2, &show_rename);
878 1.1 riastrad }
879