root/tools/perf/examples/bpf/augmented_syscalls.c

/* [<][>][^][v][top][bottom][index][help] */
   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * Augment syscalls with the contents of the pointer arguments.
   4  *
   5  * Test it with:
   6  *
   7  * perf trace -e tools/perf/examples/bpf/augmented_syscalls.c cat /etc/passwd > /dev/null
   8  *
   9  * It'll catch some openat syscalls related to the dynamic linked and
  10  * the last one should be the one for '/etc/passwd'.
  11  *
  12  * This matches what is marshalled into the raw_syscall:sys_enter payload
  13  * expected by the 'perf trace' beautifiers, and can be used by them, that will
  14  * check if perf_sample->raw_data is more than what is expected for each
  15  * syscalls:sys_{enter,exit}_SYSCALL tracepoint, uing the extra data as the
  16  * contents of pointer arguments.
  17  */
  18 
  19 #include <stdio.h>
  20 #include <linux/socket.h>
  21 
  22 /* bpf-output associated map */
  23 bpf_map(__augmented_syscalls__, PERF_EVENT_ARRAY, int, u32, __NR_CPUS__);
  24 
  25 struct syscall_exit_args {
  26         unsigned long long common_tp_fields;
  27         long               syscall_nr;
  28         long               ret;
  29 };
  30 
  31 struct augmented_filename {
  32         unsigned int    size;
  33         int             reserved;
  34         char            value[256];
  35 };
  36 
  37 #define augmented_filename_syscall(syscall)                                                     \
  38 struct augmented_enter_##syscall##_args {                                                       \
  39         struct syscall_enter_##syscall##_args   args;                                           \
  40         struct augmented_filename               filename;                                       \
  41 };                                                                                              \
  42 int syscall_enter(syscall)(struct syscall_enter_##syscall##_args *args)                         \
  43 {                                                                                               \
  44         struct augmented_enter_##syscall##_args augmented_args = { .filename.reserved = 0, };   \
  45         unsigned int len = sizeof(augmented_args);                                              \
  46         probe_read(&augmented_args.args, sizeof(augmented_args.args), args);                    \
  47         augmented_args.filename.size = probe_read_str(&augmented_args.filename.value,           \
  48                                                       sizeof(augmented_args.filename.value),    \
  49                                                       args->filename_ptr);                      \
  50         if (augmented_args.filename.size < sizeof(augmented_args.filename.value)) {             \
  51                 len -= sizeof(augmented_args.filename.value) - augmented_args.filename.size;    \
  52                 len &= sizeof(augmented_args.filename.value) - 1;                               \
  53         }                                                                                       \
  54         /* If perf_event_output fails, return non-zero so that it gets recorded unaugmented */  \
  55         return perf_event_output(args, &__augmented_syscalls__, BPF_F_CURRENT_CPU,              \
  56                                  &augmented_args, len);                                         \
  57 }                                                                                               \
  58 int syscall_exit(syscall)(struct syscall_exit_args *args)                                       \
  59 {                                                                                               \
  60        return 1; /* 0 as soon as we start copying data returned by the kernel, e.g. 'read' */   \
  61 }
  62 
  63 struct syscall_enter_openat_args {
  64         unsigned long long common_tp_fields;
  65         long               syscall_nr;
  66         long               dfd;
  67         char               *filename_ptr;
  68         long               flags;
  69         long               mode;
  70 };
  71 
  72 augmented_filename_syscall(openat);
  73 
  74 struct syscall_enter_open_args {
  75         unsigned long long common_tp_fields;
  76         long               syscall_nr;
  77         char               *filename_ptr;
  78         long               flags;
  79         long               mode;
  80 };
  81 
  82 augmented_filename_syscall(open);
  83 
  84 struct syscall_enter_inotify_add_watch_args {
  85         unsigned long long common_tp_fields;
  86         long               syscall_nr;
  87         long               fd;
  88         char               *filename_ptr;
  89         long               mask;
  90 };
  91 
  92 augmented_filename_syscall(inotify_add_watch);
  93 
  94 struct statbuf;
  95 
  96 struct syscall_enter_newstat_args {
  97         unsigned long long common_tp_fields;
  98         long               syscall_nr;
  99         char               *filename_ptr;
 100         struct stat        *statbuf;
 101 };
 102 
 103 augmented_filename_syscall(newstat);
 104 
 105 #ifndef _K_SS_MAXSIZE
 106 #define _K_SS_MAXSIZE 128
 107 #endif
 108 
 109 #define augmented_sockaddr_syscall(syscall)                                             \
 110 struct augmented_enter_##syscall##_args {                                                       \
 111         struct syscall_enter_##syscall##_args   args;                                           \
 112         struct sockaddr_storage                 addr;                                           \
 113 };                                                                                              \
 114 int syscall_enter(syscall)(struct syscall_enter_##syscall##_args *args)                         \
 115 {                                                                                               \
 116         struct augmented_enter_##syscall##_args augmented_args;                                 \
 117         unsigned long addrlen = sizeof(augmented_args.addr);                                    \
 118         probe_read(&augmented_args.args, sizeof(augmented_args.args), args);                    \
 119 /* FIXME_CLANG_OPTIMIZATION_THAT_ACCESSES_USER_CONTROLLED_ADDRLEN_DESPITE_THIS_CHECK */         \
 120 /*      if (addrlen > augmented_args.args.addrlen)                                   */         \
 121 /*              addrlen = augmented_args.args.addrlen;                               */         \
 122 /*                                                                                   */         \
 123         probe_read(&augmented_args.addr, addrlen, args->addr_ptr);                              \
 124         /* If perf_event_output fails, return non-zero so that it gets recorded unaugmented */  \
 125         return perf_event_output(args, &__augmented_syscalls__, BPF_F_CURRENT_CPU,              \
 126                                  &augmented_args,                                               \
 127                                 sizeof(augmented_args) - sizeof(augmented_args.addr) + addrlen);\
 128 }                                                                                               \
 129 int syscall_exit(syscall)(struct syscall_exit_args *args)                                       \
 130 {                                                                                               \
 131        return 1; /* 0 as soon as we start copying data returned by the kernel, e.g. 'read' */   \
 132 }
 133 
 134 struct sockaddr;
 135 
 136 struct syscall_enter_bind_args {
 137         unsigned long long common_tp_fields;
 138         long               syscall_nr;
 139         long               fd;
 140         struct sockaddr    *addr_ptr;
 141         unsigned long      addrlen;
 142 };
 143 
 144 augmented_sockaddr_syscall(bind);
 145 
 146 struct syscall_enter_connect_args {
 147         unsigned long long common_tp_fields;
 148         long               syscall_nr;
 149         long               fd;
 150         struct sockaddr    *addr_ptr;
 151         unsigned long      addrlen;
 152 };
 153 
 154 augmented_sockaddr_syscall(connect);
 155 
 156 struct syscall_enter_sendto_args {
 157         unsigned long long common_tp_fields;
 158         long               syscall_nr;
 159         long               fd;
 160         void               *buff;
 161         long               len;
 162         unsigned long      flags;
 163         struct sockaddr    *addr_ptr;
 164         long               addr_len;
 165 };
 166 
 167 augmented_sockaddr_syscall(sendto);
 168 
 169 license(GPL);

/* [<][>][^][v][top][bottom][index][help] */