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