1 1.15 rillig /* $NetBSD: filemon_ktrace.c,v 1.15 2021/07/31 09:30:17 rillig Exp $ */ 2 1.1 riastrad 3 1.13 rillig /* 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.10 rillig /*ARGSUSED*/ 134 1.1 riastrad static int 135 1.1 riastrad compare_filemon_states(void *cookie, const void *na, const void *nb) 136 1.1 riastrad { 137 1.1 riastrad const struct filemon_state *Sa = na; 138 1.1 riastrad const struct filemon_state *Sb = nb; 139 1.1 riastrad 140 1.1 riastrad if (Sa->key.pid < Sb->key.pid) 141 1.1 riastrad return -1; 142 1.1 riastrad if (Sa->key.pid > Sb->key.pid) 143 1.1 riastrad return +1; 144 1.1 riastrad if (Sa->key.lid < Sb->key.lid) 145 1.1 riastrad return -1; 146 1.1 riastrad if (Sa->key.lid > Sb->key.lid) 147 1.1 riastrad return +1; 148 1.1 riastrad return 0; 149 1.1 riastrad } 150 1.1 riastrad 151 1.10 rillig /*ARGSUSED*/ 152 1.1 riastrad static int 153 1.1 riastrad compare_filemon_key(void *cookie, const void *n, const void *k) 154 1.1 riastrad { 155 1.1 riastrad const struct filemon_state *S = n; 156 1.1 riastrad const struct filemon_key *key = k; 157 1.1 riastrad 158 1.1 riastrad if (S->key.pid < key->pid) 159 1.1 riastrad return -1; 160 1.1 riastrad if (S->key.pid > key->pid) 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 if (S->key.lid > key->lid) 165 1.1 riastrad return +1; 166 1.1 riastrad return 0; 167 1.1 riastrad } 168 1.1 riastrad 169 1.1 riastrad static const rb_tree_ops_t filemon_rb_ops = { 170 1.1 riastrad .rbto_compare_nodes = &compare_filemon_states, 171 1.1 riastrad .rbto_compare_key = &compare_filemon_key, 172 1.1 riastrad .rbto_node_offset = offsetof(struct filemon_state, node), 173 1.1 riastrad .rbto_context = NULL, 174 1.1 riastrad }; 175 1.1 riastrad 176 1.1 riastrad /* 177 1.1 riastrad * filemon_path() 178 1.1 riastrad * 179 1.1 riastrad * Return a pointer to a constant string denoting the `path' of 180 1.1 riastrad * the filemon. 181 1.1 riastrad */ 182 1.1 riastrad const char * 183 1.1 riastrad filemon_path(void) 184 1.1 riastrad { 185 1.1 riastrad 186 1.1 riastrad return "ktrace"; 187 1.1 riastrad } 188 1.1 riastrad 189 1.1 riastrad /* 190 1.1 riastrad * filemon_open() 191 1.1 riastrad * 192 1.1 riastrad * Allocate a filemon descriptor. Returns NULL and sets errno on 193 1.1 riastrad * failure. 194 1.1 riastrad */ 195 1.1 riastrad struct filemon * 196 1.1 riastrad filemon_open(void) 197 1.1 riastrad { 198 1.1 riastrad struct filemon *F; 199 1.1 riastrad int ktrpipe[2]; 200 1.1 riastrad int error; 201 1.1 riastrad 202 1.1 riastrad /* Allocate and zero a struct filemon object. */ 203 1.4 rillig F = calloc(1, sizeof *F); 204 1.1 riastrad if (F == NULL) 205 1.1 riastrad return NULL; 206 1.1 riastrad 207 1.1 riastrad /* Create a pipe for ktrace events. */ 208 1.1 riastrad if (pipe2(ktrpipe, O_CLOEXEC|O_NONBLOCK) == -1) { 209 1.1 riastrad error = errno; 210 1.1 riastrad goto fail0; 211 1.1 riastrad } 212 1.1 riastrad 213 1.1 riastrad /* Create a file stream for reading the ktrace events. */ 214 1.1 riastrad if ((F->in = fdopen(ktrpipe[0], "r")) == NULL) { 215 1.1 riastrad error = errno; 216 1.1 riastrad goto fail1; 217 1.1 riastrad } 218 1.1 riastrad ktrpipe[0] = -1; /* claimed by fdopen */ 219 1.1 riastrad 220 1.1 riastrad /* 221 1.1 riastrad * Set the fd for writing ktrace events and initialize the 222 1.1 riastrad * rbtree. The rest can be safely initialized to zero. 223 1.1 riastrad */ 224 1.1 riastrad F->ktrfd = ktrpipe[1]; 225 1.1 riastrad rb_tree_init(&F->active, &filemon_rb_ops); 226 1.1 riastrad 227 1.1 riastrad /* Success! */ 228 1.1 riastrad return F; 229 1.1 riastrad 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.6 rillig if (error != 0) { 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.6 rillig if (error != 0) { 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.3 rillig 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.12 rillig if (F->resid > 0) { 522 1.1 riastrad nread = fread(F->p, 1, F->resid, F->in); 523 1.1 riastrad if (nread == 0) { 524 1.12 rillig if (feof(F->in) != 0) 525 1.1 riastrad return 0; 526 1.11 rillig assert(ferror(F->in) != 0); 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.12 rillig if (F->resid > 0) /* 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.10 rillig syscall_enter( 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.11 rillig if (ret->ktr_error != 0 && 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.11 rillig if (ret->ktr_error != 0 && 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.10 rillig 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.10 rillig /*ARGSUSED*/ 756 1.1 riastrad static struct filemon_state * 757 1.1 riastrad filemon_sys_chdir(struct filemon *F, const struct filemon_key *key, 758 1.1 riastrad const struct ktr_syscall *call) 759 1.1 riastrad { 760 1.10 rillig return syscall_enter(key, call, 1, &show_chdir); 761 1.1 riastrad } 762 1.1 riastrad 763 1.14 rillig /* TODO: monitor fchdir as well */ 764 1.14 rillig 765 1.10 rillig /*ARGSUSED*/ 766 1.1 riastrad static struct filemon_state * 767 1.1 riastrad filemon_sys_execve(struct filemon *F, const struct filemon_key *key, 768 1.1 riastrad const struct ktr_syscall *call) 769 1.1 riastrad { 770 1.10 rillig return syscall_enter(key, call, 1, &show_execve); 771 1.1 riastrad } 772 1.1 riastrad 773 1.1 riastrad static struct filemon_state * 774 1.1 riastrad filemon_sys_exit(struct filemon *F, const struct filemon_key *key, 775 1.1 riastrad const struct ktr_syscall *call) 776 1.1 riastrad { 777 1.1 riastrad const register_t *args = (const void *)&call[1]; 778 1.3 rillig int status = (int)args[0]; 779 1.1 riastrad 780 1.9 rillig if (F->out != NULL) { 781 1.1 riastrad fprintf(F->out, "X %jd %d\n", (intmax_t)key->pid, status); 782 1.1 riastrad if (key->pid == F->child) { 783 1.1 riastrad fprintf(F->out, "# Bye bye\n"); 784 1.1 riastrad F->child = 0; 785 1.1 riastrad } 786 1.1 riastrad } 787 1.1 riastrad return NULL; 788 1.1 riastrad } 789 1.1 riastrad 790 1.10 rillig /*ARGSUSED*/ 791 1.1 riastrad static struct filemon_state * 792 1.1 riastrad filemon_sys_fork(struct filemon *F, const struct filemon_key *key, 793 1.1 riastrad const struct ktr_syscall *call) 794 1.1 riastrad { 795 1.10 rillig return syscall_enter(key, call, 0, &show_fork); 796 1.1 riastrad } 797 1.1 riastrad 798 1.10 rillig /*ARGSUSED*/ 799 1.1 riastrad static struct filemon_state * 800 1.1 riastrad filemon_sys_link(struct filemon *F, const struct filemon_key *key, 801 1.1 riastrad const struct ktr_syscall *call) 802 1.1 riastrad { 803 1.10 rillig return syscall_enter(key, call, 2, &show_link); 804 1.1 riastrad } 805 1.1 riastrad 806 1.10 rillig /*ARGSUSED*/ 807 1.1 riastrad static struct filemon_state * 808 1.1 riastrad filemon_sys_open(struct filemon *F, const struct filemon_key *key, 809 1.1 riastrad const struct ktr_syscall *call) 810 1.1 riastrad { 811 1.1 riastrad const register_t *args = (const void *)&call[1]; 812 1.1 riastrad int flags; 813 1.1 riastrad 814 1.1 riastrad if (call->ktr_argsize < 2) 815 1.1 riastrad return NULL; 816 1.3 rillig flags = (int)args[1]; 817 1.1 riastrad 818 1.1 riastrad if ((flags & O_RDWR) == O_RDWR) 819 1.10 rillig return syscall_enter(key, call, 1, &show_open_readwrite); 820 1.1 riastrad else if ((flags & O_WRONLY) == O_WRONLY) 821 1.10 rillig return syscall_enter(key, call, 1, &show_open_write); 822 1.1 riastrad else if ((flags & O_RDONLY) == O_RDONLY) 823 1.10 rillig return syscall_enter(key, call, 1, &show_open_read); 824 1.1 riastrad else 825 1.1 riastrad return NULL; /* XXX Do we care if no read or write? */ 826 1.1 riastrad } 827 1.1 riastrad 828 1.10 rillig /*ARGSUSED*/ 829 1.1 riastrad static struct filemon_state * 830 1.1 riastrad filemon_sys_openat(struct filemon *F, const struct filemon_key *key, 831 1.1 riastrad const struct ktr_syscall *call) 832 1.1 riastrad { 833 1.1 riastrad const register_t *args = (const void *)&call[1]; 834 1.1 riastrad int flags, fd; 835 1.1 riastrad 836 1.14 rillig /* 837 1.14 rillig * XXX: In the .meta log, the base directory is missing, which makes 838 1.14 rillig * all references to relative pathnames useless. 839 1.14 rillig */ 840 1.14 rillig 841 1.1 riastrad if (call->ktr_argsize < 3) 842 1.1 riastrad return NULL; 843 1.3 rillig fd = (int)args[0]; 844 1.3 rillig flags = (int)args[2]; 845 1.1 riastrad 846 1.1 riastrad if (fd == AT_CWD) { 847 1.1 riastrad if ((flags & O_RDWR) == O_RDWR) 848 1.10 rillig return syscall_enter(key, call, 1, 849 1.1 riastrad &show_open_readwrite); 850 1.1 riastrad else if ((flags & O_WRONLY) == O_WRONLY) 851 1.10 rillig return syscall_enter(key, call, 1, &show_open_write); 852 1.1 riastrad else if ((flags & O_RDONLY) == O_RDONLY) 853 1.10 rillig return syscall_enter(key, call, 1, &show_open_read); 854 1.1 riastrad else 855 1.1 riastrad return NULL; 856 1.1 riastrad } else { 857 1.1 riastrad if ((flags & O_RDWR) == O_RDWR) 858 1.10 rillig return syscall_enter(key, call, 1, 859 1.1 riastrad &show_openat_readwrite); 860 1.1 riastrad else if ((flags & O_WRONLY) == O_WRONLY) 861 1.10 rillig return syscall_enter(key, call, 1, &show_openat_write); 862 1.1 riastrad else if ((flags & O_RDONLY) == O_RDONLY) 863 1.10 rillig return syscall_enter(key, call, 1, &show_openat_read); 864 1.1 riastrad else 865 1.1 riastrad return NULL; 866 1.1 riastrad } 867 1.1 riastrad } 868 1.1 riastrad 869 1.14 rillig /* TODO: monitor the other *at syscalls as well, not only openat. */ 870 1.14 rillig 871 1.10 rillig /*ARGSUSED*/ 872 1.1 riastrad static struct filemon_state * 873 1.1 riastrad filemon_sys_symlink(struct filemon *F, const struct filemon_key *key, 874 1.1 riastrad const struct ktr_syscall *call) 875 1.1 riastrad { 876 1.10 rillig return syscall_enter(key, call, 2, &show_symlink); 877 1.1 riastrad } 878 1.1 riastrad 879 1.10 rillig /*ARGSUSED*/ 880 1.1 riastrad static struct filemon_state * 881 1.1 riastrad filemon_sys_unlink(struct filemon *F, const struct filemon_key *key, 882 1.1 riastrad const struct ktr_syscall *call) 883 1.1 riastrad { 884 1.10 rillig return syscall_enter(key, call, 1, &show_unlink); 885 1.1 riastrad } 886 1.1 riastrad 887 1.10 rillig /*ARGSUSED*/ 888 1.1 riastrad static struct filemon_state * 889 1.1 riastrad filemon_sys_rename(struct filemon *F, const struct filemon_key *key, 890 1.1 riastrad const struct ktr_syscall *call) 891 1.1 riastrad { 892 1.10 rillig return syscall_enter(key, call, 2, &show_rename); 893 1.1 riastrad } 894