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); 170