1/* $NetBSD: filemon_ktrace.c,v 1.2 2020/01/19 20:22:57 riastradh 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 61struct filemon; 62struct filemon_key; 63struct filemon_state; 64 65typedef struct filemon_state *filemon_syscall_t(struct filemon *, 66 const struct filemon_key *, const struct ktr_syscall *); 67 68static filemon_syscall_t filemon_sys_chdir; 69static filemon_syscall_t filemon_sys_execve; 70static filemon_syscall_t filemon_sys_exit; 71static filemon_syscall_t filemon_sys_fork; 72static filemon_syscall_t filemon_sys_link; 73static filemon_syscall_t filemon_sys_open; 74static filemon_syscall_t filemon_sys_openat; 75static filemon_syscall_t filemon_sys_symlink; 76static filemon_syscall_t filemon_sys_unlink; 77static filemon_syscall_t filemon_sys_rename; 78 79static 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 92struct 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 119struct 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 133static int 134compare_filemon_states(void *cookie, const void *na, const void *nb) 135{ 136 const struct filemon_state *Sa = na; 137 const struct filemon_state *Sb = nb; 138 139 if (Sa->key.pid < Sb->key.pid) 140 return -1; 141 if (Sa->key.pid > Sb->key.pid) 142 return +1; 143 if (Sa->key.lid < Sb->key.lid) 144 return -1; 145 if (Sa->key.lid > Sb->key.lid) 146 return +1; 147 return 0; 148} 149 150static int 151compare_filemon_key(void *cookie, const void *n, const void *k) 152{ 153 const struct filemon_state *S = n; 154 const struct filemon_key *key = k; 155 156 if (S->key.pid < key->pid) 157 return -1; 158 if (S->key.pid > key->pid) 159 return +1; 160 if (S->key.lid < key->lid) 161 return -1; 162 if (S->key.lid > key->lid) 163 return +1; 164 return 0; 165} 166 167static const rb_tree_ops_t filemon_rb_ops = { 168 .rbto_compare_nodes = &compare_filemon_states, 169 .rbto_compare_key = &compare_filemon_key, 170 .rbto_node_offset = offsetof(struct filemon_state, node), 171 .rbto_context = NULL, 172}; 173 174/* 175 * filemon_path() 176 * 177 * Return a pointer to a constant string denoting the `path' of 178 * the filemon. 179 */ 180const char * 181filemon_path(void) 182{ 183 184 return "ktrace"; 185} 186 187/* 188 * filemon_open() 189 * 190 * Allocate a filemon descriptor. Returns NULL and sets errno on 191 * failure. 192 */ 193struct filemon * 194filemon_open(void) 195{ 196 struct filemon *F; 197 int ktrpipe[2]; 198 int error; 199 200 /* Allocate and zero a struct filemon object. */ 201 F = calloc(1, sizeof(*F)); 202 if (F == NULL) 203 return NULL; 204 205 /* Create a pipe for ktrace events. */ 206 if (pipe2(ktrpipe, O_CLOEXEC|O_NONBLOCK) == -1) { 207 error = errno; 208 goto fail0; 209 } 210 211 /* Create a file stream for reading the ktrace events. */ 212 if ((F->in = fdopen(ktrpipe[0], "r")) == NULL) { 213 error = errno; 214 goto fail1; 215 } 216 ktrpipe[0] = -1; /* claimed by fdopen */ 217 218 /* 219 * Set the fd for writing ktrace events and initialize the 220 * rbtree. The rest can be safely initialized to zero. 221 */ 222 F->ktrfd = ktrpipe[1]; 223 rb_tree_init(&F->active, &filemon_rb_ops); 224 225 /* Success! */ 226 return F; 227 228fail2: __unused 229 (void)fclose(F->in); 230fail1: (void)close(ktrpipe[0]); 231 (void)close(ktrpipe[1]); 232fail0: 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 */ 245static int 246filemon_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) { 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 */ 281int 282filemon_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 */ 315void 316filemon_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 */ 328int 329filemon_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 */ 350int 351filemon_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) { 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 */ 392int 393filemon_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 */ 407static void 408filemon_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 */ 510int 511filemon_process(struct filemon *F) 512{ 513 size_t nread; 514 515top: /* 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) { 522 nread = fread(F->p, 1, F->resid, F->in); 523 if (nread == 0) { 524 if (feof(F->in)) 525 return 0; 526 assert(ferror(F->in)); 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) /* 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 584static struct filemon_state * 585syscall_enter(struct filemon *F, 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 608static void 609show_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 && 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 638static void 639show_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 && 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 656static void 657show_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 663static void 664show_execve(struct filemon *F, const struct filemon_state *S, 665 const struct ktr_sysret *ret) 666{ 667 return show_paths(F, S, ret, "E"); 668} 669 670static void 671show_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 677static void 678show_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 684static void 685show_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 691static void 692show_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 698static void 699show_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 706static void 707show_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 715static void 716show_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 724static void 725show_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 734static void 735show_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 741static void 742show_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 748static void 749show_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 755static struct filemon_state * 756filemon_sys_chdir(struct filemon *F, const struct filemon_key *key, 757 const struct ktr_syscall *call) 758{ 759 return syscall_enter(F, key, call, 1, &show_chdir); 760} 761 762static struct filemon_state * 763filemon_sys_execve(struct filemon *F, const struct filemon_key *key, 764 const struct ktr_syscall *call) 765{ 766 return syscall_enter(F, key, call, 1, &show_execve); 767} 768 769static struct filemon_state * 770filemon_sys_exit(struct filemon *F, const struct filemon_key *key, 771 const struct ktr_syscall *call) 772{ 773 const register_t *args = (const void *)&call[1]; 774 int status = args[0]; 775 776 if (F->out) { 777 fprintf(F->out, "X %jd %d\n", (intmax_t)key->pid, status); 778 if (key->pid == F->child) { 779 fprintf(F->out, "# Bye bye\n"); 780 F->child = 0; 781 } 782 } 783 return NULL; 784} 785 786static struct filemon_state * 787filemon_sys_fork(struct filemon *F, const struct filemon_key *key, 788 const struct ktr_syscall *call) 789{ 790 return syscall_enter(F, key, call, 0, &show_fork); 791} 792 793static struct filemon_state * 794filemon_sys_link(struct filemon *F, const struct filemon_key *key, 795 const struct ktr_syscall *call) 796{ 797 return syscall_enter(F, key, call, 2, &show_link); 798} 799 800static struct filemon_state * 801filemon_sys_open(struct filemon *F, const struct filemon_key *key, 802 const struct ktr_syscall *call) 803{ 804 const register_t *args = (const void *)&call[1]; 805 int flags; 806 807 if (call->ktr_argsize < 2) 808 return NULL; 809 flags = args[1]; 810 811 if ((flags & O_RDWR) == O_RDWR) 812 return syscall_enter(F, key, call, 1, &show_open_readwrite); 813 else if ((flags & O_WRONLY) == O_WRONLY) 814 return syscall_enter(F, key, call, 1, &show_open_write); 815 else if ((flags & O_RDONLY) == O_RDONLY) 816 return syscall_enter(F, key, call, 1, &show_open_read); 817 else 818 return NULL; /* XXX Do we care if no read or write? */ 819} 820 821static struct filemon_state * 822filemon_sys_openat(struct filemon *F, const struct filemon_key *key, 823 const struct ktr_syscall *call) 824{ 825 const register_t *args = (const void *)&call[1]; 826 int flags, fd; 827 828 if (call->ktr_argsize < 3) 829 return NULL; 830 fd = args[0]; 831 flags = args[2]; 832 833 if (fd == AT_CWD) { 834 if ((flags & O_RDWR) == O_RDWR) 835 return syscall_enter(F, key, call, 1, 836 &show_open_readwrite); 837 else if ((flags & O_WRONLY) == O_WRONLY) 838 return syscall_enter(F, key, call, 1, 839 &show_open_write); 840 else if ((flags & O_RDONLY) == O_RDONLY) 841 return syscall_enter(F, key, call, 1, &show_open_read); 842 else 843 return NULL; 844 } else { 845 if ((flags & O_RDWR) == O_RDWR) 846 return syscall_enter(F, key, call, 1, 847 &show_openat_readwrite); 848 else if ((flags & O_WRONLY) == O_WRONLY) 849 return syscall_enter(F, key, call, 1, 850 &show_openat_write); 851 else if ((flags & O_RDONLY) == O_RDONLY) 852 return syscall_enter(F, key, call, 1, 853 &show_openat_read); 854 else 855 return NULL; 856 } 857} 858 859static struct filemon_state * 860filemon_sys_symlink(struct filemon *F, const struct filemon_key *key, 861 const struct ktr_syscall *call) 862{ 863 return syscall_enter(F, key, call, 2, &show_symlink); 864} 865 866static struct filemon_state * 867filemon_sys_unlink(struct filemon *F, const struct filemon_key *key, 868 const struct ktr_syscall *call) 869{ 870 return syscall_enter(F, key, call, 1, &show_unlink); 871} 872 873static struct filemon_state * 874filemon_sys_rename(struct filemon *F, const struct filemon_key *key, 875 const struct ktr_syscall *call) 876{ 877 return syscall_enter(F, key, call, 2, &show_rename); 878} 879