]> granicus.if.org Git - strace/blob - bpf.c
mem: handle potential error from sysconf(_SC_PAGESIZE)
[strace] / bpf.c
1 /*
2  * Copyright (c) 2015-2017 Dmitry V. Levin <ldv@altlinux.org>
3  * Copyright (c) 2017 Quentin Monnet <quentin.monnet@6wind.com>
4  * Copyright (c) 2015-2018 The strace developers.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. The name of the author may not be used to endorse or promote products
16  *    derived from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
30 #include "defs.h"
31 #include "print_fields.h"
32
33 #ifdef HAVE_LINUX_BPF_H
34 # include <linux/bpf.h>
35 #endif
36
37 #include "bpf_attr.h"
38
39 #include "xlat/bpf_commands.h"
40 #include "xlat/bpf_file_mode_flags.h"
41 #include "xlat/bpf_map_types.h"
42 #include "xlat/bpf_map_flags.h"
43 #include "xlat/bpf_prog_types.h"
44 #include "xlat/bpf_prog_flags.h"
45 #include "xlat/bpf_map_update_elem_flags.h"
46 #include "xlat/bpf_attach_type.h"
47 #include "xlat/bpf_attach_flags.h"
48 #include "xlat/bpf_query_flags.h"
49 #include "xlat/numa_node.h"
50
51 /** Storage for all the data that is needed to be stored on entering. */
52 struct bpf_priv_data {
53         bool     bpf_prog_query_stored;
54         uint32_t bpf_prog_query_prog_cnt;
55 };
56
57 #define DECL_BPF_CMD_DECODER(bpf_cmd_decoder)                           \
58 int                                                                     \
59 bpf_cmd_decoder(struct tcb *const tcp,                                  \
60                 const kernel_ulong_t addr,                              \
61                 const unsigned int size,                                \
62                 void *const data,                                       \
63                 struct bpf_priv_data *priv)                             \
64 /* End of DECL_BPF_CMD_DECODER definition. */
65
66 #define BEGIN_BPF_CMD_DECODER(bpf_cmd)                                  \
67         static DECL_BPF_CMD_DECODER(decode_ ## bpf_cmd)                 \
68         {                                                               \
69                 struct bpf_cmd ## _struct attr = {};                    \
70                 const size_t attr_size = bpf_cmd ## _struct_size;       \
71                 const unsigned int len = MIN(size, attr_size);          \
72                 memcpy(&attr, data, len);                               \
73                 do {                                                    \
74 /* End of BEGIN_BPF_CMD_DECODER definition. */
75
76 #define END_BPF_CMD_DECODER(rval)                                       \
77                         decode_attr_extra_data(tcp, data, size, attr_size); \
78                 } while (0);                                            \
79                 tprints("}");                                           \
80                 return (rval);                                          \
81         }                                                               \
82 /* End of END_BPF_CMD_DECODER definition. */
83
84 #define BPF_CMD_ENTRY(bpf_cmd)                                          \
85         [bpf_cmd] = decode_ ## bpf_cmd
86
87 typedef DECL_BPF_CMD_DECODER((*bpf_cmd_decoder_t));
88
89 /*
90  * A note about bpf syscall decoder: it doesn't perform any size sanity checks,
91  * so even if it leads to partial copying of one of the fields, the command
92  * handler will still use the (partially-copied-from-userspace, partially
93  * zeroed) field value.  That's why we stop decoding and check for known sizes
94  * that correspond to released versions of the structure used by the specific
95  * command - it looks like the most sensible way to parse this insanity.
96  */
97
98 static int
99 decode_attr_extra_data(struct tcb *const tcp,
100                        const char *data,
101                        unsigned int size,
102                        const size_t attr_size)
103 {
104         if (size <= attr_size)
105                 return 0;
106
107         data += attr_size;
108         size -= attr_size;
109
110         unsigned int i;
111         for (i = 0; i < size; ++i) {
112                 if (data[i]) {
113                         tprints(", ");
114                         if (abbrev(tcp)) {
115                                 tprints("...");
116                         } else {
117                                 tprintf("/* bytes %zu..%zu */ ",
118                                         attr_size, attr_size + size - 1);
119                                 print_quoted_string(data, size,
120                                                     QUOTE_FORCE_HEX);
121                         }
122                         return RVAL_DECODED;
123                 }
124         }
125
126         return 0;
127 }
128
129 BEGIN_BPF_CMD_DECODER(BPF_MAP_CREATE)
130 {
131         PRINT_FIELD_XVAL("{", attr, map_type, bpf_map_types,
132                          "BPF_MAP_TYPE_???");
133         PRINT_FIELD_U(", ", attr, key_size);
134         PRINT_FIELD_U(", ", attr, value_size);
135         PRINT_FIELD_U(", ", attr, max_entries);
136
137         /* map_flags field was added in Linux commit v4.6-rc1~91^2~108^2~6. */
138         if (len <= offsetof(struct BPF_MAP_CREATE_struct, map_flags))
139                 break;
140         PRINT_FIELD_FLAGS(", ", attr, map_flags, bpf_map_flags, "BPF_F_???");
141
142         /*
143          * inner_map_fd field was added in Linux commit
144          * v4.12-rc1~64^3~373^2~2.
145          */
146         if (len <= offsetof(struct BPF_MAP_CREATE_struct, inner_map_fd))
147                 break;
148         PRINT_FIELD_FD(", ", attr, inner_map_fd, tcp);
149
150         /* numa_node field was added in Linux commit v4.14-rc1~130^2~196^2~1. */
151         if (len <= offsetof(struct BPF_MAP_CREATE_struct, numa_node))
152                 break;
153         if (attr.map_flags & BPF_F_NUMA_NODE) {
154                 /*
155                  * Kernel uses the value of -1 as a designation for "no NUMA
156                  * node specified", and even uses NUMA_NO_NODE constant;
157                  * however, the constant definition is not a part of UAPI
158                  * headers, thus we can't simply print this named constant
159                  * instead of the value. Let's force verbose xlat style instead
160                  * in order to provide the information for the user while
161                  * not hampering the availability to derive the actual value
162                  * without the access to the kernel headers.
163                  */
164                 tprints(", numa_node=");
165                 printxvals_ex(attr.numa_node, NULL,
166                               XLAT_STYLE_FMT_U | XLAT_STYLE_VERBOSE,
167                               numa_node, NULL);
168         }
169
170         /* map_name field was added in Linux commit v4.15-rc1~84^2~605^2~3. */
171         if (len <= offsetof(struct BPF_MAP_CREATE_struct, map_name))
172                 break;
173         PRINT_FIELD_CSTRING_SZ(", ", attr, map_name,
174                                MIN(sizeof(attr.map_name),
175                                    len - offsetof(struct BPF_MAP_CREATE_struct,
176                                                   map_name)));
177
178         /*
179          * map_ifindex field was added in Linux commit
180          * v4.16-rc1~123^2~145^2~5^2~8.
181          */
182         if (len <= offsetof(struct BPF_MAP_CREATE_struct, map_ifindex))
183                 break;
184         PRINT_FIELD_IFINDEX(", ", attr, map_ifindex);
185 }
186 END_BPF_CMD_DECODER(RVAL_DECODED | RVAL_FD)
187
188 BEGIN_BPF_CMD_DECODER(BPF_MAP_LOOKUP_ELEM)
189 {
190         PRINT_FIELD_FD("{", attr, map_fd, tcp);
191         PRINT_FIELD_ADDR64(", ", attr, key);
192         PRINT_FIELD_ADDR64(", ", attr, value);
193 }
194 END_BPF_CMD_DECODER(RVAL_DECODED)
195
196 BEGIN_BPF_CMD_DECODER(BPF_MAP_UPDATE_ELEM)
197 {
198         PRINT_FIELD_FD("{", attr, map_fd, tcp);
199         PRINT_FIELD_ADDR64(", ", attr, key);
200         PRINT_FIELD_ADDR64(", ", attr, value);
201         PRINT_FIELD_XVAL(", ", attr, flags, bpf_map_update_elem_flags,
202                          "BPF_???");
203 }
204 END_BPF_CMD_DECODER(RVAL_DECODED)
205
206 BEGIN_BPF_CMD_DECODER(BPF_MAP_DELETE_ELEM)
207 {
208         PRINT_FIELD_FD("{", attr, map_fd, tcp);
209         PRINT_FIELD_ADDR64(", ", attr, key);
210 }
211 END_BPF_CMD_DECODER(RVAL_DECODED)
212
213 BEGIN_BPF_CMD_DECODER(BPF_MAP_GET_NEXT_KEY)
214 {
215         PRINT_FIELD_FD("{", attr, map_fd, tcp);
216         PRINT_FIELD_ADDR64(", ", attr, key);
217         PRINT_FIELD_ADDR64(", ", attr, next_key);
218 }
219 END_BPF_CMD_DECODER(RVAL_DECODED)
220
221 BEGIN_BPF_CMD_DECODER(BPF_PROG_LOAD)
222 {
223         PRINT_FIELD_XVAL("{", attr, prog_type, bpf_prog_types,
224                          "BPF_PROG_TYPE_???");
225         PRINT_FIELD_U(", ", attr, insn_cnt);
226         PRINT_FIELD_ADDR64(", ", attr, insns);
227
228         tprintf(", license=");
229         print_big_u64_addr(attr.license);
230         printstr(tcp, attr.license);
231
232         /* log_* fields were added in Linux commit v3.18-rc1~52^2~1^2~4.  */
233         if (len <= offsetof(struct BPF_PROG_LOAD_struct, log_level))
234                 break;
235         PRINT_FIELD_U(", ", attr, log_level);
236         PRINT_FIELD_U(", ", attr, log_size);
237         PRINT_FIELD_ADDR64(", ", attr, log_buf);
238
239         /* kern_version field was added in Linux commit v4.1-rc1~84^2~50.  */
240         if (len <= offsetof(struct BPF_PROG_LOAD_struct, kern_version))
241                 break;
242         tprintf(", kern_version=KERNEL_VERSION(%u, %u, %u)",
243                 attr.kern_version >> 16,
244                 (attr.kern_version >> 8) & 0xFF,
245                 attr.kern_version & 0xFF);
246
247         /* prog_flags field was added in Linux commit v4.12-rc2~34^2~29^2~2.  */
248         if (len <= offsetof(struct BPF_PROG_LOAD_struct, prog_flags))
249                 break;
250         PRINT_FIELD_FLAGS(", ", attr, prog_flags, bpf_prog_flags, "BPF_F_???");
251
252         /* prog_name field was added in Linux commit v4.15-rc1~84^2~605^2~4. */
253         if (len <= offsetof(struct BPF_PROG_LOAD_struct, prog_name))
254                 break;
255         PRINT_FIELD_CSTRING_SZ(", ", attr, prog_name,
256                                MIN(sizeof(attr.prog_name),
257                                    len - offsetof(struct BPF_PROG_LOAD_struct,
258                                                    prog_name)));
259
260         /*
261          * prog_ifindex field was added as prog_target_ifindex in Linux commit
262          * v4.15-rc1~84^2~127^2~13 and renamed to its current name in
263          * v4.15-rc1~15^2~5^2~3^2~7.
264          */
265         if (len <= offsetof(struct BPF_PROG_LOAD_struct, prog_ifindex))
266                 break;
267         PRINT_FIELD_IFINDEX(", ", attr, prog_ifindex);
268 }
269 END_BPF_CMD_DECODER(RVAL_DECODED | RVAL_FD)
270
271 BEGIN_BPF_CMD_DECODER(BPF_OBJ_PIN)
272 {
273         tprintf("{pathname=");
274         print_big_u64_addr(attr.pathname);
275         printpath(tcp, attr.pathname);
276
277         PRINT_FIELD_FD(", ", attr, bpf_fd, tcp);
278
279         /* file_flags field was added in Linux v4.15-rc1~84^2~384^2~4 */
280         if (len <= offsetof(struct BPF_OBJ_PIN_struct, file_flags))
281                 break;
282         PRINT_FIELD_FLAGS(", ", attr, file_flags, bpf_file_mode_flags,
283                           "BPF_F_???");
284 }
285 END_BPF_CMD_DECODER(RVAL_DECODED | RVAL_FD)
286
287 #define decode_BPF_OBJ_GET decode_BPF_OBJ_PIN
288
289 BEGIN_BPF_CMD_DECODER(BPF_PROG_ATTACH)
290 {
291         PRINT_FIELD_FD("{", attr, target_fd, tcp);
292         PRINT_FIELD_FD(", ", attr, attach_bpf_fd, tcp);
293         PRINT_FIELD_XVAL(", ", attr, attach_type, bpf_attach_type, "BPF_???");
294         PRINT_FIELD_FLAGS(", ", attr, attach_flags, bpf_attach_flags,
295                           "BPF_F_???");
296 }
297 END_BPF_CMD_DECODER(RVAL_DECODED)
298
299 BEGIN_BPF_CMD_DECODER(BPF_PROG_DETACH)
300 {
301         PRINT_FIELD_FD("{", attr, target_fd, tcp);
302         PRINT_FIELD_XVAL(", ", attr, attach_type, bpf_attach_type, "BPF_???");
303 }
304 END_BPF_CMD_DECODER(RVAL_DECODED)
305
306 BEGIN_BPF_CMD_DECODER(BPF_PROG_TEST_RUN)
307 {
308         PRINT_FIELD_FD("{test={", attr, prog_fd, tcp);
309         PRINT_FIELD_U(", ", attr, retval);
310         PRINT_FIELD_U(", ", attr, data_size_in);
311         PRINT_FIELD_U(", ", attr, data_size_out);
312         PRINT_FIELD_ADDR64(", ", attr, data_in);
313         PRINT_FIELD_ADDR64(", ", attr, data_out);
314         PRINT_FIELD_U(", ", attr, repeat);
315         PRINT_FIELD_U(", ", attr, duration);
316         tprints("}");
317 }
318 END_BPF_CMD_DECODER(RVAL_DECODED)
319
320 BEGIN_BPF_CMD_DECODER(BPF_PROG_GET_NEXT_ID)
321 {
322         PRINT_FIELD_U("{", attr, start_id);
323         PRINT_FIELD_U(", ", attr, next_id);
324
325         /* open_flags field has been added in Linux v4.15-rc1~84^2~384^2~4 */
326         if (len <= offsetof(struct BPF_PROG_GET_NEXT_ID_struct, open_flags))
327                 break;
328         PRINT_FIELD_FLAGS(", ", attr, open_flags, bpf_file_mode_flags,
329                           "BPF_F_???");
330 }
331 END_BPF_CMD_DECODER(RVAL_DECODED)
332
333 #define decode_BPF_MAP_GET_NEXT_ID decode_BPF_PROG_GET_NEXT_ID
334
335 BEGIN_BPF_CMD_DECODER(BPF_PROG_GET_FD_BY_ID)
336 {
337         PRINT_FIELD_U("{", attr, prog_id);
338         PRINT_FIELD_U(", ", attr, next_id);
339
340         /* open_flags field has been added in Linux v4.15-rc1~84^2~384^2~4 */
341         if (len <= offsetof(struct BPF_PROG_GET_FD_BY_ID_struct, open_flags))
342                 break;
343         PRINT_FIELD_FLAGS(", ", attr, open_flags, bpf_file_mode_flags,
344                           "BPF_F_???");
345 }
346 END_BPF_CMD_DECODER(RVAL_DECODED)
347
348 BEGIN_BPF_CMD_DECODER(BPF_MAP_GET_FD_BY_ID)
349 {
350         PRINT_FIELD_U("{", attr, map_id);
351         PRINT_FIELD_U(", ", attr, next_id);
352
353         /* open_flags field has been added in Linux v4.15-rc1~84^2~384^2~4 */
354         if (len <= offsetof(struct BPF_MAP_GET_FD_BY_ID_struct, open_flags))
355                 break;
356         PRINT_FIELD_FLAGS(", ", attr, open_flags, bpf_file_mode_flags,
357                           "BPF_F_???");
358 }
359 END_BPF_CMD_DECODER(RVAL_DECODED)
360
361 BEGIN_BPF_CMD_DECODER(BPF_OBJ_GET_INFO_BY_FD)
362 {
363         PRINT_FIELD_FD("{info={", attr, bpf_fd, tcp);
364         PRINT_FIELD_U(", ", attr, info_len);
365         PRINT_FIELD_X(", ", attr, info);
366         tprints("}");
367 }
368 END_BPF_CMD_DECODER(RVAL_DECODED | RVAL_FD)
369
370 BEGIN_BPF_CMD_DECODER(BPF_PROG_QUERY)
371 {
372         uint64_t prog_id_buf;
373
374         if (entering(tcp)) {
375                 PRINT_FIELD_FD("{query={", attr, target_fd, tcp);
376                 PRINT_FIELD_XVAL(", ", attr, attach_type, bpf_attach_type,
377                                  "BPF_???");
378                 PRINT_FIELD_FLAGS(", ", attr, query_flags, bpf_query_flags,
379                                   "BPF_F_QUERY_???");
380                 PRINT_FIELD_FLAGS(", ", attr, attach_flags, bpf_attach_flags,
381                                   "BPF_F_???");
382
383                 tprints(", prog_ids=");
384
385                 if (!priv)
386                         priv = xcalloc(1, sizeof(*priv));
387
388                 priv->bpf_prog_query_stored = true;
389                 priv->bpf_prog_query_prog_cnt = attr.prog_cnt;
390
391                 set_tcb_priv_data(tcp, priv, free);
392
393                 return 0;
394         }
395
396         /*
397          * The issue here is that we can't pass pointers bigger than
398          * (our) kernel long ti print_array, so we opt out from decoding
399          * the array.
400          */
401         if (syserror(tcp) || attr.prog_ids > max_kaddr())
402                 printaddr64(attr.prog_ids);
403         else
404                 print_array(tcp, attr.prog_ids, attr.prog_cnt, &prog_id_buf,
405                             sizeof(prog_id_buf), umoven_or_printaddr,
406                             print_uint64_array_member, 0);
407
408         tprints(", prog_cnt=");
409         if (priv && priv->bpf_prog_query_stored
410             && priv->bpf_prog_query_prog_cnt != attr.prog_cnt)
411                 tprintf("%" PRIu32 " => ", priv->bpf_prog_query_prog_cnt);
412         tprintf("%" PRIu32, attr.prog_cnt);
413         tprints("}");
414 }
415 END_BPF_CMD_DECODER(RVAL_DECODED)
416
417 SYS_FUNC(bpf)
418 {
419         static const bpf_cmd_decoder_t bpf_cmd_decoders[] = {
420                 BPF_CMD_ENTRY(BPF_MAP_CREATE),
421                 BPF_CMD_ENTRY(BPF_MAP_LOOKUP_ELEM),
422                 BPF_CMD_ENTRY(BPF_MAP_UPDATE_ELEM),
423                 BPF_CMD_ENTRY(BPF_MAP_DELETE_ELEM),
424                 BPF_CMD_ENTRY(BPF_MAP_GET_NEXT_KEY),
425                 BPF_CMD_ENTRY(BPF_PROG_LOAD),
426                 BPF_CMD_ENTRY(BPF_OBJ_PIN),
427                 BPF_CMD_ENTRY(BPF_OBJ_GET),
428                 BPF_CMD_ENTRY(BPF_PROG_ATTACH),
429                 BPF_CMD_ENTRY(BPF_PROG_DETACH),
430                 BPF_CMD_ENTRY(BPF_PROG_TEST_RUN),
431                 BPF_CMD_ENTRY(BPF_PROG_GET_NEXT_ID),
432                 BPF_CMD_ENTRY(BPF_MAP_GET_NEXT_ID),
433                 BPF_CMD_ENTRY(BPF_PROG_GET_FD_BY_ID),
434                 BPF_CMD_ENTRY(BPF_MAP_GET_FD_BY_ID),
435                 BPF_CMD_ENTRY(BPF_OBJ_GET_INFO_BY_FD),
436                 BPF_CMD_ENTRY(BPF_PROG_QUERY),
437         };
438
439         static char *buf;
440         struct bpf_priv_data *priv = NULL;
441
442         const unsigned int cmd = tcp->u_arg[0];
443         const kernel_ulong_t addr = tcp->u_arg[1];
444         const unsigned int size = tcp->u_arg[2];
445         int rc = RVAL_DECODED;
446
447         if (!buf)
448                 buf = xmalloc(get_pagesize());
449
450         if (entering(tcp)) {
451                 printxval(bpf_commands, cmd, "BPF_???");
452                 tprints(", ");
453         } else {
454                 priv = get_tcb_priv_data(tcp);
455         }
456
457         if (size > 0
458             && size <= get_pagesize()
459             && cmd < ARRAY_SIZE(bpf_cmd_decoders)
460             && bpf_cmd_decoders[cmd]) {
461                 if (!umoven_or_printaddr_ignore_syserror(tcp, addr, size, buf))
462                         rc = bpf_cmd_decoders[cmd](tcp, addr, size, buf, priv);
463         } else {
464                 printaddr(addr);
465         }
466
467         if (exiting(tcp) || (rc & RVAL_DECODED))
468                 tprintf(", %u", size);
469
470         return rc;
471 }