b.liu | e958203 | 2025-04-17 19:18:16 +0800 | [diff] [blame^] | 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); |