filemon_ktrace.c revision 1.8 1 1.8 rillig /* $NetBSD: filemon_ktrace.c,v 1.8 2020/11/29 09:27:40 rillig 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.8 rillig #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.5 rillig int ktrfd; /* kernel writes ktrace events here */
94 1.5 rillig FILE *in; /* we read ktrace events from here */
95 1.5 rillig 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.4 rillig 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 (void)fclose(F->in);
229 1.1 riastrad fail1: (void)close(ktrpipe[0]);
230 1.1 riastrad (void)close(ktrpipe[1]);
231 1.1 riastrad fail0: free(F);
232 1.1 riastrad errno = error;
233 1.1 riastrad return NULL;
234 1.1 riastrad }
235 1.1 riastrad
236 1.1 riastrad /*
237 1.1 riastrad * filemon_closefd(F)
238 1.1 riastrad *
239 1.1 riastrad * Internal subroutine to try to flush and close the output file.
240 1.1 riastrad * If F is not open for output, do nothing. Never leaves F open
241 1.1 riastrad * for output even on failure. Returns 0 on success; sets errno
242 1.1 riastrad * and return -1 on failure.
243 1.1 riastrad */
244 1.1 riastrad static int
245 1.1 riastrad filemon_closefd(struct filemon *F)
246 1.1 riastrad {
247 1.1 riastrad int error = 0;
248 1.1 riastrad
249 1.1 riastrad /* If we're not open, nothing to do. */
250 1.1 riastrad if (F->out == NULL)
251 1.1 riastrad return 0;
252 1.1 riastrad
253 1.1 riastrad /*
254 1.1 riastrad * Flush it, close it, and null it unconditionally, but be
255 1.1 riastrad * careful to return the earliest error in errno.
256 1.1 riastrad */
257 1.1 riastrad if (fflush(F->out) == EOF && error == 0)
258 1.1 riastrad error = errno;
259 1.1 riastrad if (fclose(F->out) == EOF && error == 0)
260 1.1 riastrad error = errno;
261 1.1 riastrad F->out = NULL;
262 1.1 riastrad
263 1.1 riastrad /* Set errno and return -1 if anything went wrong. */
264 1.6 rillig if (error != 0) {
265 1.1 riastrad errno = error;
266 1.1 riastrad return -1;
267 1.1 riastrad }
268 1.1 riastrad
269 1.1 riastrad /* Success! */
270 1.1 riastrad return 0;
271 1.1 riastrad }
272 1.1 riastrad
273 1.1 riastrad /*
274 1.1 riastrad * filemon_setfd(F, fd)
275 1.1 riastrad *
276 1.1 riastrad * Cause filemon activity on F to be sent to fd. Claims ownership
277 1.1 riastrad * of fd; caller should not use fd afterward, and any duplicates
278 1.1 riastrad * of fd may see their file positions changed.
279 1.1 riastrad */
280 1.1 riastrad int
281 1.1 riastrad filemon_setfd(struct filemon *F, int fd)
282 1.1 riastrad {
283 1.1 riastrad
284 1.1 riastrad /*
285 1.1 riastrad * Close an existing output file if done. Fail now if there's
286 1.1 riastrad * an error closing.
287 1.1 riastrad */
288 1.1 riastrad if ((filemon_closefd(F)) == -1)
289 1.1 riastrad return -1;
290 1.1 riastrad assert(F->out == NULL);
291 1.1 riastrad
292 1.1 riastrad /* Open a file stream and claim ownership of the fd. */
293 1.1 riastrad if ((F->out = fdopen(fd, "a")) == NULL)
294 1.1 riastrad return -1;
295 1.1 riastrad
296 1.1 riastrad /*
297 1.1 riastrad * Print the opening output. Any failure will be deferred
298 1.1 riastrad * until closing. For hysterical raisins, we show the parent
299 1.1 riastrad * pid, not the child pid.
300 1.1 riastrad */
301 1.1 riastrad fprintf(F->out, "# filemon version 4\n");
302 1.1 riastrad fprintf(F->out, "# Target pid %jd\n", (intmax_t)getpid());
303 1.1 riastrad fprintf(F->out, "V 4\n");
304 1.1 riastrad
305 1.1 riastrad /* Success! */
306 1.1 riastrad return 0;
307 1.1 riastrad }
308 1.1 riastrad
309 1.1 riastrad /*
310 1.1 riastrad * filemon_setpid_parent(F, pid)
311 1.1 riastrad *
312 1.1 riastrad * Set the traced pid, from the parent. Never fails.
313 1.1 riastrad */
314 1.1 riastrad void
315 1.1 riastrad filemon_setpid_parent(struct filemon *F, pid_t pid)
316 1.1 riastrad {
317 1.1 riastrad
318 1.1 riastrad F->child = pid;
319 1.1 riastrad }
320 1.1 riastrad
321 1.1 riastrad /*
322 1.1 riastrad * filemon_setpid_child(F, pid)
323 1.1 riastrad *
324 1.1 riastrad * Set the traced pid, from the child. Returns 0 on success; sets
325 1.1 riastrad * errno and returns -1 on failure.
326 1.1 riastrad */
327 1.1 riastrad int
328 1.1 riastrad filemon_setpid_child(const struct filemon *F, pid_t pid)
329 1.1 riastrad {
330 1.1 riastrad int ops, trpoints;
331 1.1 riastrad
332 1.1 riastrad ops = KTROP_SET|KTRFLAG_DESCEND;
333 1.1 riastrad trpoints = KTRFACv2;
334 1.1 riastrad trpoints |= KTRFAC_SYSCALL|KTRFAC_NAMEI|KTRFAC_SYSRET;
335 1.1 riastrad trpoints |= KTRFAC_INHERIT;
336 1.1 riastrad if (fktrace(F->ktrfd, ops, trpoints, pid) == -1)
337 1.1 riastrad return -1;
338 1.1 riastrad
339 1.1 riastrad return 0;
340 1.1 riastrad }
341 1.1 riastrad
342 1.1 riastrad /*
343 1.1 riastrad * filemon_close(F)
344 1.1 riastrad *
345 1.1 riastrad * Close F for output if necessary, and free a filemon descriptor.
346 1.1 riastrad * Returns 0 on success; sets errno and returns -1 on failure, but
347 1.1 riastrad * frees the filemon descriptor either way;
348 1.1 riastrad */
349 1.1 riastrad int
350 1.1 riastrad filemon_close(struct filemon *F)
351 1.1 riastrad {
352 1.1 riastrad struct filemon_state *S;
353 1.1 riastrad int error = 0;
354 1.1 riastrad
355 1.1 riastrad /* Close for output. */
356 1.1 riastrad if (filemon_closefd(F) == -1 && error == 0)
357 1.1 riastrad error = errno;
358 1.1 riastrad
359 1.1 riastrad /* Close the ktrace pipe. */
360 1.1 riastrad if (fclose(F->in) == EOF && error == 0)
361 1.1 riastrad error = errno;
362 1.1 riastrad if (close(F->ktrfd) == -1 && error == 0)
363 1.1 riastrad error = errno;
364 1.1 riastrad
365 1.1 riastrad /* Free any active records. */
366 1.1 riastrad while ((S = RB_TREE_MIN(&F->active)) != NULL) {
367 1.1 riastrad rb_tree_remove_node(&F->active, S);
368 1.1 riastrad free(S);
369 1.1 riastrad }
370 1.1 riastrad
371 1.1 riastrad /* Free the filemon descriptor. */
372 1.1 riastrad free(F);
373 1.1 riastrad
374 1.1 riastrad /* Set errno and return -1 if anything went wrong. */
375 1.6 rillig if (error != 0) {
376 1.1 riastrad errno = error;
377 1.1 riastrad return -1;
378 1.1 riastrad }
379 1.1 riastrad
380 1.1 riastrad /* Success! */
381 1.1 riastrad return 0;
382 1.1 riastrad }
383 1.1 riastrad
384 1.1 riastrad /*
385 1.1 riastrad * filemon_readfd(F)
386 1.1 riastrad *
387 1.1 riastrad * Returns a file descriptor which will select/poll ready for read
388 1.1 riastrad * when there are filemon events to be processed by
389 1.1 riastrad * filemon_process, or -1 if anything has gone wrong.
390 1.1 riastrad */
391 1.1 riastrad int
392 1.1 riastrad filemon_readfd(const struct filemon *F)
393 1.1 riastrad {
394 1.1 riastrad
395 1.1 riastrad if (F->state == FILEMON_ERROR)
396 1.1 riastrad return -1;
397 1.1 riastrad return fileno(F->in);
398 1.1 riastrad }
399 1.1 riastrad
400 1.1 riastrad /*
401 1.1 riastrad * filemon_dispatch(F)
402 1.1 riastrad *
403 1.1 riastrad * Internal subroutine to dispatch a filemon ktrace event.
404 1.1 riastrad * Silently ignore events that we don't recognize.
405 1.1 riastrad */
406 1.1 riastrad static void
407 1.1 riastrad filemon_dispatch(struct filemon *F)
408 1.1 riastrad {
409 1.1 riastrad const struct filemon_key key = {
410 1.1 riastrad .pid = F->hdr.ktr_pid,
411 1.1 riastrad .lid = F->hdr.ktr_lid,
412 1.1 riastrad };
413 1.1 riastrad struct filemon_state *S;
414 1.1 riastrad
415 1.1 riastrad switch (F->hdr.ktr_type) {
416 1.1 riastrad case KTR_SYSCALL: {
417 1.1 riastrad struct ktr_syscall *call = &F->payload.syscall;
418 1.1 riastrad struct filemon_state *S1;
419 1.1 riastrad
420 1.1 riastrad /* Validate the syscall code. */
421 1.1 riastrad if (call->ktr_code < 0 ||
422 1.1 riastrad (size_t)call->ktr_code >= __arraycount(filemon_syscalls) ||
423 1.1 riastrad filemon_syscalls[call->ktr_code] == NULL)
424 1.1 riastrad break;
425 1.1 riastrad
426 1.1 riastrad /*
427 1.1 riastrad * Invoke the syscall-specific logic to create a new
428 1.1 riastrad * active state.
429 1.1 riastrad */
430 1.1 riastrad S = (*filemon_syscalls[call->ktr_code])(F, &key, call);
431 1.1 riastrad if (S == NULL)
432 1.1 riastrad break;
433 1.1 riastrad
434 1.1 riastrad /*
435 1.1 riastrad * Insert the active state, or ignore it if there
436 1.1 riastrad * already is one.
437 1.1 riastrad *
438 1.1 riastrad * Collisions shouldn't happen because the states are
439 1.1 riastrad * keyed by <pid,lid>, in which syscalls should happen
440 1.1 riastrad * sequentially in CALL/RET pairs, but let's be
441 1.1 riastrad * defensive.
442 1.1 riastrad */
443 1.1 riastrad S1 = rb_tree_insert_node(&F->active, S);
444 1.1 riastrad if (S1 != S) {
445 1.1 riastrad /* XXX Which one to drop? */
446 1.1 riastrad free(S);
447 1.1 riastrad break;
448 1.1 riastrad }
449 1.1 riastrad break;
450 1.1 riastrad }
451 1.1 riastrad case KTR_NAMEI:
452 1.1 riastrad /* Find an active syscall state, or drop it. */
453 1.1 riastrad S = rb_tree_find_node(&F->active, &key);
454 1.1 riastrad if (S == NULL)
455 1.1 riastrad break;
456 1.1 riastrad /* Find the position of the next path, or drop it. */
457 1.1 riastrad if (S->i >= S->npath)
458 1.1 riastrad break;
459 1.1 riastrad /* Record the path. */
460 1.1 riastrad S->path[S->i++] = strndup(F->payload.namei,
461 1.1 riastrad sizeof F->payload.namei);
462 1.1 riastrad break;
463 1.1 riastrad case KTR_SYSRET: {
464 1.1 riastrad struct ktr_sysret *ret = &F->payload.sysret;
465 1.1 riastrad unsigned i;
466 1.1 riastrad
467 1.1 riastrad /* Find and remove an active syscall state, or drop it. */
468 1.1 riastrad S = rb_tree_find_node(&F->active, &key);
469 1.1 riastrad if (S == NULL)
470 1.1 riastrad break;
471 1.1 riastrad rb_tree_remove_node(&F->active, S);
472 1.1 riastrad
473 1.1 riastrad /*
474 1.1 riastrad * If the active syscall state matches this return,
475 1.1 riastrad * invoke the syscall-specific logic to show a filemon
476 1.1 riastrad * event.
477 1.1 riastrad */
478 1.1 riastrad /* XXX What to do if syscall code doesn't match? */
479 1.1 riastrad if (S->i == S->npath && S->syscode == ret->ktr_code)
480 1.3 rillig S->show(F, S, ret);
481 1.1 riastrad
482 1.1 riastrad /* Free the state now that it is no longer active. */
483 1.1 riastrad for (i = 0; i < S->i; i++)
484 1.1 riastrad free(S->path[i]);
485 1.1 riastrad free(S);
486 1.1 riastrad break;
487 1.1 riastrad }
488 1.1 riastrad default:
489 1.1 riastrad /* Ignore all other ktrace events. */
490 1.1 riastrad break;
491 1.1 riastrad }
492 1.1 riastrad }
493 1.1 riastrad
494 1.1 riastrad /*
495 1.1 riastrad * filemon_process(F)
496 1.1 riastrad *
497 1.1 riastrad * Process all pending events after filemon_readfd(F) has
498 1.1 riastrad * selected/polled ready for read.
499 1.1 riastrad *
500 1.1 riastrad * Returns -1 on failure, 0 on end of events, and anything else if
501 1.1 riastrad * there may be more events.
502 1.1 riastrad *
503 1.1 riastrad * XXX What about fairness to other activities in the event loop?
504 1.1 riastrad * If we stop while there's events buffered in F->in, then select
505 1.1 riastrad * or poll may not return ready even though there's work queued up
506 1.1 riastrad * in the buffer of F->in, but if we don't stop then ktrace events
507 1.1 riastrad * may overwhelm all other activity in the event loop.
508 1.1 riastrad */
509 1.1 riastrad int
510 1.1 riastrad filemon_process(struct filemon *F)
511 1.1 riastrad {
512 1.1 riastrad size_t nread;
513 1.1 riastrad
514 1.1 riastrad top: /* If the child has exited, nothing to do. */
515 1.1 riastrad /* XXX What if one thread calls exit while another is running? */
516 1.1 riastrad if (F->child == 0)
517 1.1 riastrad return 0;
518 1.1 riastrad
519 1.1 riastrad /* If we're waiting for input, read some. */
520 1.1 riastrad if (F->resid) {
521 1.1 riastrad nread = fread(F->p, 1, F->resid, F->in);
522 1.1 riastrad if (nread == 0) {
523 1.1 riastrad if (feof(F->in))
524 1.1 riastrad return 0;
525 1.1 riastrad assert(ferror(F->in));
526 1.1 riastrad /*
527 1.1 riastrad * If interrupted or would block, there may be
528 1.1 riastrad * more events. Otherwise fail.
529 1.1 riastrad */
530 1.1 riastrad if (errno == EAGAIN || errno == EINTR)
531 1.1 riastrad return 1;
532 1.1 riastrad F->state = FILEMON_ERROR;
533 1.1 riastrad F->p = NULL;
534 1.1 riastrad F->resid = 0;
535 1.1 riastrad return -1;
536 1.1 riastrad }
537 1.1 riastrad assert(nread <= F->resid);
538 1.1 riastrad F->p += nread;
539 1.1 riastrad F->resid -= nread;
540 1.1 riastrad if (F->resid) /* may be more events */
541 1.1 riastrad return 1;
542 1.1 riastrad }
543 1.1 riastrad
544 1.1 riastrad /* Process a state transition now that we've read a buffer. */
545 1.1 riastrad switch (F->state) {
546 1.1 riastrad case FILEMON_START: /* just started filemon; read header next */
547 1.1 riastrad F->state = FILEMON_HEADER;
548 1.1 riastrad F->p = (void *)&F->hdr;
549 1.1 riastrad F->resid = sizeof F->hdr;
550 1.1 riastrad goto top;
551 1.1 riastrad case FILEMON_HEADER: /* read header */
552 1.1 riastrad /* Sanity-check ktrace header; then read payload. */
553 1.1 riastrad if (F->hdr.ktr_len < 0 ||
554 1.1 riastrad (size_t)F->hdr.ktr_len > sizeof F->payload) {
555 1.1 riastrad F->state = FILEMON_ERROR;
556 1.1 riastrad F->p = NULL;
557 1.1 riastrad F->resid = 0;
558 1.1 riastrad errno = EIO;
559 1.1 riastrad return -1;
560 1.1 riastrad }
561 1.1 riastrad F->state = FILEMON_PAYLOAD;
562 1.1 riastrad F->p = (void *)&F->payload;
563 1.1 riastrad F->resid = (size_t)F->hdr.ktr_len;
564 1.1 riastrad goto top;
565 1.1 riastrad case FILEMON_PAYLOAD: /* read header and payload */
566 1.1 riastrad /* Dispatch ktrace event; then read next header. */
567 1.1 riastrad filemon_dispatch(F);
568 1.1 riastrad F->state = FILEMON_HEADER;
569 1.1 riastrad F->p = (void *)&F->hdr;
570 1.1 riastrad F->resid = sizeof F->hdr;
571 1.1 riastrad goto top;
572 1.1 riastrad default: /* paranoia */
573 1.1 riastrad F->state = FILEMON_ERROR;
574 1.1 riastrad /*FALLTHROUGH*/
575 1.1 riastrad case FILEMON_ERROR: /* persistent error indicator */
576 1.1 riastrad F->p = NULL;
577 1.1 riastrad F->resid = 0;
578 1.1 riastrad errno = EIO;
579 1.1 riastrad return -1;
580 1.1 riastrad }
581 1.1 riastrad }
582 1.1 riastrad
583 1.1 riastrad static struct filemon_state *
584 1.1 riastrad syscall_enter(struct filemon *F,
585 1.1 riastrad const struct filemon_key *key, const struct ktr_syscall *call,
586 1.1 riastrad unsigned npath,
587 1.1 riastrad void (*show)(struct filemon *, const struct filemon_state *,
588 1.1 riastrad const struct ktr_sysret *))
589 1.1 riastrad {
590 1.1 riastrad struct filemon_state *S;
591 1.1 riastrad unsigned i;
592 1.1 riastrad
593 1.1 riastrad S = calloc(1, offsetof(struct filemon_state, path[npath]));
594 1.1 riastrad if (S == NULL)
595 1.1 riastrad return NULL;
596 1.1 riastrad S->key = *key;
597 1.1 riastrad S->show = show;
598 1.1 riastrad S->syscode = call->ktr_code;
599 1.1 riastrad S->i = 0;
600 1.1 riastrad S->npath = npath;
601 1.1 riastrad for (i = 0; i < npath; i++)
602 1.1 riastrad S->path[i] = NULL; /* paranoia */
603 1.1 riastrad
604 1.1 riastrad return S;
605 1.1 riastrad }
606 1.1 riastrad
607 1.1 riastrad static void
608 1.1 riastrad show_paths(struct filemon *F, const struct filemon_state *S,
609 1.1 riastrad const struct ktr_sysret *ret, const char *prefix)
610 1.1 riastrad {
611 1.1 riastrad unsigned i;
612 1.1 riastrad
613 1.1 riastrad /* Caller must ensure all paths have been specified. */
614 1.1 riastrad assert(S->i == S->npath);
615 1.1 riastrad
616 1.1 riastrad /*
617 1.1 riastrad * Ignore it if it failed or yielded EJUSTRETURN (-2), or if
618 1.1 riastrad * we're not producing output.
619 1.1 riastrad */
620 1.1 riastrad if (ret->ktr_error && ret->ktr_error != -2)
621 1.1 riastrad return;
622 1.1 riastrad if (F->out == NULL)
623 1.1 riastrad return;
624 1.1 riastrad
625 1.1 riastrad /*
626 1.1 riastrad * Print the prefix, pid, and paths -- with the paths quoted if
627 1.1 riastrad * there's more than one.
628 1.1 riastrad */
629 1.1 riastrad fprintf(F->out, "%s %jd", prefix, (intmax_t)S->key.pid);
630 1.1 riastrad for (i = 0; i < S->npath; i++) {
631 1.1 riastrad const char *q = S->npath > 1 ? "'" : "";
632 1.1 riastrad fprintf(F->out, " %s%s%s", q, S->path[i], q);
633 1.1 riastrad }
634 1.1 riastrad fprintf(F->out, "\n");
635 1.1 riastrad }
636 1.1 riastrad
637 1.1 riastrad static void
638 1.1 riastrad show_retval(struct filemon *F, const struct filemon_state *S,
639 1.1 riastrad const struct ktr_sysret *ret, const char *prefix)
640 1.1 riastrad {
641 1.1 riastrad
642 1.1 riastrad /*
643 1.1 riastrad * Ignore it if it failed or yielded EJUSTRETURN (-2), or if
644 1.1 riastrad * we're not producing output.
645 1.1 riastrad */
646 1.1 riastrad if (ret->ktr_error && ret->ktr_error != -2)
647 1.1 riastrad return;
648 1.1 riastrad if (F->out == NULL)
649 1.1 riastrad return;
650 1.1 riastrad
651 1.1 riastrad fprintf(F->out, "%s %jd %jd\n", prefix, (intmax_t)S->key.pid,
652 1.1 riastrad (intmax_t)ret->ktr_retval);
653 1.1 riastrad }
654 1.1 riastrad
655 1.1 riastrad static void
656 1.1 riastrad show_chdir(struct filemon *F, const struct filemon_state *S,
657 1.1 riastrad const struct ktr_sysret *ret)
658 1.1 riastrad {
659 1.1 riastrad show_paths(F, S, ret, "C");
660 1.1 riastrad }
661 1.1 riastrad
662 1.1 riastrad static void
663 1.1 riastrad show_execve(struct filemon *F, const struct filemon_state *S,
664 1.1 riastrad const struct ktr_sysret *ret)
665 1.1 riastrad {
666 1.1 riastrad return show_paths(F, S, ret, "E");
667 1.1 riastrad }
668 1.1 riastrad
669 1.1 riastrad static void
670 1.1 riastrad show_fork(struct filemon *F, const struct filemon_state *S,
671 1.1 riastrad const struct ktr_sysret *ret)
672 1.1 riastrad {
673 1.1 riastrad show_retval(F, S, ret, "F");
674 1.1 riastrad }
675 1.1 riastrad
676 1.1 riastrad static void
677 1.1 riastrad show_link(struct filemon *F, const struct filemon_state *S,
678 1.1 riastrad const struct ktr_sysret *ret)
679 1.1 riastrad {
680 1.1 riastrad show_paths(F, S, ret, "L"); /* XXX same as symlink */
681 1.1 riastrad }
682 1.1 riastrad
683 1.1 riastrad static void
684 1.1 riastrad show_open_read(struct filemon *F, const struct filemon_state *S,
685 1.1 riastrad const struct ktr_sysret *ret)
686 1.1 riastrad {
687 1.1 riastrad show_paths(F, S, ret, "R");
688 1.1 riastrad }
689 1.1 riastrad
690 1.1 riastrad static void
691 1.1 riastrad show_open_write(struct filemon *F, const struct filemon_state *S,
692 1.1 riastrad const struct ktr_sysret *ret)
693 1.1 riastrad {
694 1.1 riastrad show_paths(F, S, ret, "W");
695 1.1 riastrad }
696 1.1 riastrad
697 1.1 riastrad static void
698 1.1 riastrad show_open_readwrite(struct filemon *F, const struct filemon_state *S,
699 1.1 riastrad const struct ktr_sysret *ret)
700 1.1 riastrad {
701 1.1 riastrad show_paths(F, S, ret, "R");
702 1.1 riastrad show_paths(F, S, ret, "W");
703 1.1 riastrad }
704 1.1 riastrad
705 1.1 riastrad static void
706 1.1 riastrad show_openat_read(struct filemon *F, const struct filemon_state *S,
707 1.1 riastrad const struct ktr_sysret *ret)
708 1.1 riastrad {
709 1.1 riastrad if (S->path[0][0] != '/')
710 1.1 riastrad show_paths(F, S, ret, "A");
711 1.1 riastrad show_paths(F, S, ret, "R");
712 1.1 riastrad }
713 1.1 riastrad
714 1.1 riastrad static void
715 1.1 riastrad show_openat_write(struct filemon *F, const struct filemon_state *S,
716 1.1 riastrad const struct ktr_sysret *ret)
717 1.1 riastrad {
718 1.1 riastrad if (S->path[0][0] != '/')
719 1.1 riastrad show_paths(F, S, ret, "A");
720 1.1 riastrad show_paths(F, S, ret, "W");
721 1.1 riastrad }
722 1.1 riastrad
723 1.1 riastrad static void
724 1.1 riastrad show_openat_readwrite(struct filemon *F, const struct filemon_state *S,
725 1.1 riastrad const struct ktr_sysret *ret)
726 1.1 riastrad {
727 1.1 riastrad if (S->path[0][0] != '/')
728 1.1 riastrad show_paths(F, S, ret, "A");
729 1.1 riastrad show_paths(F, S, ret, "R");
730 1.1 riastrad show_paths(F, S, ret, "W");
731 1.1 riastrad }
732 1.1 riastrad
733 1.1 riastrad static void
734 1.1 riastrad show_symlink(struct filemon *F, const struct filemon_state *S,
735 1.1 riastrad const struct ktr_sysret *ret)
736 1.1 riastrad {
737 1.1 riastrad show_paths(F, S, ret, "L"); /* XXX same as link */
738 1.1 riastrad }
739 1.1 riastrad
740 1.1 riastrad static void
741 1.1 riastrad show_unlink(struct filemon *F, const struct filemon_state *S,
742 1.1 riastrad const struct ktr_sysret *ret)
743 1.1 riastrad {
744 1.1 riastrad show_paths(F, S, ret, "D");
745 1.1 riastrad }
746 1.1 riastrad
747 1.1 riastrad static void
748 1.1 riastrad show_rename(struct filemon *F, const struct filemon_state *S,
749 1.1 riastrad const struct ktr_sysret *ret)
750 1.1 riastrad {
751 1.1 riastrad show_paths(F, S, ret, "M");
752 1.1 riastrad }
753 1.1 riastrad
754 1.1 riastrad static struct filemon_state *
755 1.1 riastrad filemon_sys_chdir(struct filemon *F, const struct filemon_key *key,
756 1.1 riastrad const struct ktr_syscall *call)
757 1.1 riastrad {
758 1.1 riastrad return syscall_enter(F, key, call, 1, &show_chdir);
759 1.1 riastrad }
760 1.1 riastrad
761 1.1 riastrad static struct filemon_state *
762 1.1 riastrad filemon_sys_execve(struct filemon *F, const struct filemon_key *key,
763 1.1 riastrad const struct ktr_syscall *call)
764 1.1 riastrad {
765 1.1 riastrad return syscall_enter(F, key, call, 1, &show_execve);
766 1.1 riastrad }
767 1.1 riastrad
768 1.1 riastrad static struct filemon_state *
769 1.1 riastrad filemon_sys_exit(struct filemon *F, const struct filemon_key *key,
770 1.1 riastrad const struct ktr_syscall *call)
771 1.1 riastrad {
772 1.1 riastrad const register_t *args = (const void *)&call[1];
773 1.3 rillig int status = (int)args[0];
774 1.1 riastrad
775 1.1 riastrad if (F->out) {
776 1.1 riastrad fprintf(F->out, "X %jd %d\n", (intmax_t)key->pid, status);
777 1.1 riastrad if (key->pid == F->child) {
778 1.1 riastrad fprintf(F->out, "# Bye bye\n");
779 1.1 riastrad F->child = 0;
780 1.1 riastrad }
781 1.1 riastrad }
782 1.1 riastrad return NULL;
783 1.1 riastrad }
784 1.1 riastrad
785 1.1 riastrad static struct filemon_state *
786 1.1 riastrad filemon_sys_fork(struct filemon *F, const struct filemon_key *key,
787 1.1 riastrad const struct ktr_syscall *call)
788 1.1 riastrad {
789 1.1 riastrad return syscall_enter(F, key, call, 0, &show_fork);
790 1.1 riastrad }
791 1.1 riastrad
792 1.1 riastrad static struct filemon_state *
793 1.1 riastrad filemon_sys_link(struct filemon *F, const struct filemon_key *key,
794 1.1 riastrad const struct ktr_syscall *call)
795 1.1 riastrad {
796 1.1 riastrad return syscall_enter(F, key, call, 2, &show_link);
797 1.1 riastrad }
798 1.1 riastrad
799 1.1 riastrad static struct filemon_state *
800 1.1 riastrad filemon_sys_open(struct filemon *F, const struct filemon_key *key,
801 1.1 riastrad const struct ktr_syscall *call)
802 1.1 riastrad {
803 1.1 riastrad const register_t *args = (const void *)&call[1];
804 1.1 riastrad int flags;
805 1.1 riastrad
806 1.1 riastrad if (call->ktr_argsize < 2)
807 1.1 riastrad return NULL;
808 1.3 rillig flags = (int)args[1];
809 1.1 riastrad
810 1.1 riastrad if ((flags & O_RDWR) == O_RDWR)
811 1.1 riastrad return syscall_enter(F, key, call, 1, &show_open_readwrite);
812 1.1 riastrad else if ((flags & O_WRONLY) == O_WRONLY)
813 1.1 riastrad return syscall_enter(F, key, call, 1, &show_open_write);
814 1.1 riastrad else if ((flags & O_RDONLY) == O_RDONLY)
815 1.1 riastrad return syscall_enter(F, key, call, 1, &show_open_read);
816 1.1 riastrad else
817 1.1 riastrad return NULL; /* XXX Do we care if no read or write? */
818 1.1 riastrad }
819 1.1 riastrad
820 1.1 riastrad static struct filemon_state *
821 1.1 riastrad filemon_sys_openat(struct filemon *F, const struct filemon_key *key,
822 1.1 riastrad const struct ktr_syscall *call)
823 1.1 riastrad {
824 1.1 riastrad const register_t *args = (const void *)&call[1];
825 1.1 riastrad int flags, fd;
826 1.1 riastrad
827 1.1 riastrad if (call->ktr_argsize < 3)
828 1.1 riastrad return NULL;
829 1.3 rillig fd = (int)args[0];
830 1.3 rillig flags = (int)args[2];
831 1.1 riastrad
832 1.1 riastrad if (fd == AT_CWD) {
833 1.1 riastrad if ((flags & O_RDWR) == O_RDWR)
834 1.1 riastrad return syscall_enter(F, key, call, 1,
835 1.1 riastrad &show_open_readwrite);
836 1.1 riastrad else if ((flags & O_WRONLY) == O_WRONLY)
837 1.1 riastrad return syscall_enter(F, key, call, 1,
838 1.1 riastrad &show_open_write);
839 1.1 riastrad else if ((flags & O_RDONLY) == O_RDONLY)
840 1.1 riastrad return syscall_enter(F, key, call, 1, &show_open_read);
841 1.1 riastrad else
842 1.1 riastrad return NULL;
843 1.1 riastrad } else {
844 1.1 riastrad if ((flags & O_RDWR) == O_RDWR)
845 1.1 riastrad return syscall_enter(F, key, call, 1,
846 1.1 riastrad &show_openat_readwrite);
847 1.1 riastrad else if ((flags & O_WRONLY) == O_WRONLY)
848 1.1 riastrad return syscall_enter(F, key, call, 1,
849 1.1 riastrad &show_openat_write);
850 1.1 riastrad else if ((flags & O_RDONLY) == O_RDONLY)
851 1.1 riastrad return syscall_enter(F, key, call, 1,
852 1.1 riastrad &show_openat_read);
853 1.1 riastrad else
854 1.1 riastrad return NULL;
855 1.1 riastrad }
856 1.1 riastrad }
857 1.1 riastrad
858 1.1 riastrad static struct filemon_state *
859 1.1 riastrad filemon_sys_symlink(struct filemon *F, const struct filemon_key *key,
860 1.1 riastrad const struct ktr_syscall *call)
861 1.1 riastrad {
862 1.1 riastrad return syscall_enter(F, key, call, 2, &show_symlink);
863 1.1 riastrad }
864 1.1 riastrad
865 1.1 riastrad static struct filemon_state *
866 1.1 riastrad filemon_sys_unlink(struct filemon *F, const struct filemon_key *key,
867 1.1 riastrad const struct ktr_syscall *call)
868 1.1 riastrad {
869 1.1 riastrad return syscall_enter(F, key, call, 1, &show_unlink);
870 1.1 riastrad }
871 1.1 riastrad
872 1.1 riastrad static struct filemon_state *
873 1.1 riastrad filemon_sys_rename(struct filemon *F, const struct filemon_key *key,
874 1.1 riastrad const struct ktr_syscall *call)
875 1.1 riastrad {
876 1.1 riastrad return syscall_enter(F, key, call, 2, &show_rename);
877 1.1 riastrad }
878