at v4.20 173 lines 5.2 kB view raw
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 22struct bpf_map SEC("maps") __augmented_syscalls__ = { 23 .type = BPF_MAP_TYPE_PERF_EVENT_ARRAY, 24 .key_size = sizeof(int), 25 .value_size = sizeof(u32), 26 .max_entries = __NR_CPUS__, 27}; 28 29struct syscall_exit_args { 30 unsigned long long common_tp_fields; 31 long syscall_nr; 32 long ret; 33}; 34 35struct augmented_filename { 36 unsigned int size; 37 int reserved; 38 char value[256]; 39}; 40 41#define augmented_filename_syscall(syscall) \ 42struct augmented_enter_##syscall##_args { \ 43 struct syscall_enter_##syscall##_args args; \ 44 struct augmented_filename filename; \ 45}; \ 46int syscall_enter(syscall)(struct syscall_enter_##syscall##_args *args) \ 47{ \ 48 struct augmented_enter_##syscall##_args augmented_args = { .filename.reserved = 0, }; \ 49 unsigned int len = sizeof(augmented_args); \ 50 probe_read(&augmented_args.args, sizeof(augmented_args.args), args); \ 51 augmented_args.filename.size = probe_read_str(&augmented_args.filename.value, \ 52 sizeof(augmented_args.filename.value), \ 53 args->filename_ptr); \ 54 if (augmented_args.filename.size < sizeof(augmented_args.filename.value)) { \ 55 len -= sizeof(augmented_args.filename.value) - augmented_args.filename.size; \ 56 len &= sizeof(augmented_args.filename.value) - 1; \ 57 } \ 58 perf_event_output(args, &__augmented_syscalls__, BPF_F_CURRENT_CPU, \ 59 &augmented_args, len); \ 60 return 0; \ 61} \ 62int syscall_exit(syscall)(struct syscall_exit_args *args) \ 63{ \ 64 return 1; /* 0 as soon as we start copying data returned by the kernel, e.g. 'read' */ \ 65} 66 67struct syscall_enter_openat_args { 68 unsigned long long common_tp_fields; 69 long syscall_nr; 70 long dfd; 71 char *filename_ptr; 72 long flags; 73 long mode; 74}; 75 76augmented_filename_syscall(openat); 77 78struct syscall_enter_open_args { 79 unsigned long long common_tp_fields; 80 long syscall_nr; 81 char *filename_ptr; 82 long flags; 83 long mode; 84}; 85 86augmented_filename_syscall(open); 87 88struct syscall_enter_inotify_add_watch_args { 89 unsigned long long common_tp_fields; 90 long syscall_nr; 91 long fd; 92 char *filename_ptr; 93 long mask; 94}; 95 96augmented_filename_syscall(inotify_add_watch); 97 98struct statbuf; 99 100struct syscall_enter_newstat_args { 101 unsigned long long common_tp_fields; 102 long syscall_nr; 103 char *filename_ptr; 104 struct stat *statbuf; 105}; 106 107augmented_filename_syscall(newstat); 108 109#ifndef _K_SS_MAXSIZE 110#define _K_SS_MAXSIZE 128 111#endif 112 113#define augmented_sockaddr_syscall(syscall) \ 114struct augmented_enter_##syscall##_args { \ 115 struct syscall_enter_##syscall##_args args; \ 116 struct sockaddr_storage addr; \ 117}; \ 118int syscall_enter(syscall)(struct syscall_enter_##syscall##_args *args) \ 119{ \ 120 struct augmented_enter_##syscall##_args augmented_args; \ 121 unsigned long addrlen = sizeof(augmented_args.addr); \ 122 probe_read(&augmented_args.args, sizeof(augmented_args.args), args); \ 123/* FIXME_CLANG_OPTIMIZATION_THAT_ACCESSES_USER_CONTROLLED_ADDRLEN_DESPITE_THIS_CHECK */ \ 124/* if (addrlen > augmented_args.args.addrlen) */ \ 125/* addrlen = augmented_args.args.addrlen; */ \ 126/* */ \ 127 probe_read(&augmented_args.addr, addrlen, args->addr_ptr); \ 128 perf_event_output(args, &__augmented_syscalls__, BPF_F_CURRENT_CPU, \ 129 &augmented_args, \ 130 sizeof(augmented_args) - sizeof(augmented_args.addr) + addrlen); \ 131 return 0; \ 132} \ 133int syscall_exit(syscall)(struct syscall_exit_args *args) \ 134{ \ 135 return 1; /* 0 as soon as we start copying data returned by the kernel, e.g. 'read' */ \ 136} 137 138struct sockaddr; 139 140struct syscall_enter_bind_args { 141 unsigned long long common_tp_fields; 142 long syscall_nr; 143 long fd; 144 struct sockaddr *addr_ptr; 145 unsigned long addrlen; 146}; 147 148augmented_sockaddr_syscall(bind); 149 150struct syscall_enter_connect_args { 151 unsigned long long common_tp_fields; 152 long syscall_nr; 153 long fd; 154 struct sockaddr *addr_ptr; 155 unsigned long addrlen; 156}; 157 158augmented_sockaddr_syscall(connect); 159 160struct syscall_enter_sendto_args { 161 unsigned long long common_tp_fields; 162 long syscall_nr; 163 long fd; 164 void *buff; 165 long len; 166 unsigned long flags; 167 struct sockaddr *addr_ptr; 168 long addr_len; 169}; 170 171augmented_sockaddr_syscall(sendto); 172 173license(GPL);