Linux-libre 5.3.12-gnu
[librecmc/linux-libre.git] / tools / perf / examples / bpf / augmented_syscalls.c
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);