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.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
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.
31 #include "print_fields.h"
33 #ifdef HAVE_LINUX_BPF_H
34 # include <linux/bpf.h>
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"
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;
57 #define DECL_BPF_CMD_DECODER(bpf_cmd_decoder) \
59 bpf_cmd_decoder(struct tcb *const tcp, \
60 const kernel_ulong_t addr, \
61 const unsigned int size, \
63 struct bpf_priv_data *priv) \
64 /* End of DECL_BPF_CMD_DECODER definition. */
66 #define BEGIN_BPF_CMD_DECODER(bpf_cmd) \
67 static DECL_BPF_CMD_DECODER(decode_ ## bpf_cmd) \
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); \
74 /* End of BEGIN_BPF_CMD_DECODER definition. */
76 #define END_BPF_CMD_DECODER(rval) \
77 decode_attr_extra_data(tcp, data, size, attr_size); \
82 /* End of END_BPF_CMD_DECODER definition. */
84 #define BPF_CMD_ENTRY(bpf_cmd) \
85 [bpf_cmd] = decode_ ## bpf_cmd
87 typedef DECL_BPF_CMD_DECODER((*bpf_cmd_decoder_t));
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.
99 decode_attr_extra_data(struct tcb *const tcp,
102 const size_t attr_size)
104 if (size <= attr_size)
111 for (i = 0; i < size; ++i) {
117 tprintf("/* bytes %zu..%zu */ ",
118 attr_size, attr_size + size - 1);
119 print_quoted_string(data, size,
129 BEGIN_BPF_CMD_DECODER(BPF_MAP_CREATE)
131 PRINT_FIELD_XVAL("{", attr, map_type, bpf_map_types,
133 PRINT_FIELD_U(", ", attr, key_size);
134 PRINT_FIELD_U(", ", attr, value_size);
135 PRINT_FIELD_U(", ", attr, max_entries);
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))
140 PRINT_FIELD_FLAGS(", ", attr, map_flags, bpf_map_flags, "BPF_F_???");
143 * inner_map_fd field was added in Linux commit
144 * v4.12-rc1~64^3~373^2~2.
146 if (len <= offsetof(struct BPF_MAP_CREATE_struct, inner_map_fd))
148 PRINT_FIELD_FD(", ", attr, inner_map_fd, tcp);
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))
153 if (attr.map_flags & BPF_F_NUMA_NODE) {
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.
164 tprints(", numa_node=");
165 printxvals_ex(attr.numa_node, NULL,
166 XLAT_STYLE_FMT_U | XLAT_STYLE_VERBOSE,
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))
173 PRINT_FIELD_CSTRING_SZ(", ", attr, map_name,
174 MIN(sizeof(attr.map_name),
175 len - offsetof(struct BPF_MAP_CREATE_struct,
179 * map_ifindex field was added in Linux commit
180 * v4.16-rc1~123^2~145^2~5^2~8.
182 if (len <= offsetof(struct BPF_MAP_CREATE_struct, map_ifindex))
184 PRINT_FIELD_IFINDEX(", ", attr, map_ifindex);
186 END_BPF_CMD_DECODER(RVAL_DECODED | RVAL_FD)
188 BEGIN_BPF_CMD_DECODER(BPF_MAP_LOOKUP_ELEM)
190 PRINT_FIELD_FD("{", attr, map_fd, tcp);
191 PRINT_FIELD_ADDR64(", ", attr, key);
192 PRINT_FIELD_ADDR64(", ", attr, value);
194 END_BPF_CMD_DECODER(RVAL_DECODED)
196 BEGIN_BPF_CMD_DECODER(BPF_MAP_UPDATE_ELEM)
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,
204 END_BPF_CMD_DECODER(RVAL_DECODED)
206 BEGIN_BPF_CMD_DECODER(BPF_MAP_DELETE_ELEM)
208 PRINT_FIELD_FD("{", attr, map_fd, tcp);
209 PRINT_FIELD_ADDR64(", ", attr, key);
211 END_BPF_CMD_DECODER(RVAL_DECODED)
213 BEGIN_BPF_CMD_DECODER(BPF_MAP_GET_NEXT_KEY)
215 PRINT_FIELD_FD("{", attr, map_fd, tcp);
216 PRINT_FIELD_ADDR64(", ", attr, key);
217 PRINT_FIELD_ADDR64(", ", attr, next_key);
219 END_BPF_CMD_DECODER(RVAL_DECODED)
221 BEGIN_BPF_CMD_DECODER(BPF_PROG_LOAD)
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);
228 tprintf(", license=");
229 print_big_u64_addr(attr.license);
230 printstr(tcp, attr.license);
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))
235 PRINT_FIELD_U(", ", attr, log_level);
236 PRINT_FIELD_U(", ", attr, log_size);
237 PRINT_FIELD_ADDR64(", ", attr, log_buf);
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))
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);
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))
250 PRINT_FIELD_FLAGS(", ", attr, prog_flags, bpf_prog_flags, "BPF_F_???");
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))
255 PRINT_FIELD_CSTRING_SZ(", ", attr, prog_name,
256 MIN(sizeof(attr.prog_name),
257 len - offsetof(struct BPF_PROG_LOAD_struct,
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.
265 if (len <= offsetof(struct BPF_PROG_LOAD_struct, prog_ifindex))
267 PRINT_FIELD_IFINDEX(", ", attr, prog_ifindex);
269 END_BPF_CMD_DECODER(RVAL_DECODED | RVAL_FD)
271 BEGIN_BPF_CMD_DECODER(BPF_OBJ_PIN)
273 tprintf("{pathname=");
274 print_big_u64_addr(attr.pathname);
275 printpath(tcp, attr.pathname);
277 PRINT_FIELD_FD(", ", attr, bpf_fd, tcp);
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))
282 PRINT_FIELD_FLAGS(", ", attr, file_flags, bpf_file_mode_flags,
285 END_BPF_CMD_DECODER(RVAL_DECODED | RVAL_FD)
287 #define decode_BPF_OBJ_GET decode_BPF_OBJ_PIN
289 BEGIN_BPF_CMD_DECODER(BPF_PROG_ATTACH)
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,
297 END_BPF_CMD_DECODER(RVAL_DECODED)
299 BEGIN_BPF_CMD_DECODER(BPF_PROG_DETACH)
301 PRINT_FIELD_FD("{", attr, target_fd, tcp);
302 PRINT_FIELD_XVAL(", ", attr, attach_type, bpf_attach_type, "BPF_???");
304 END_BPF_CMD_DECODER(RVAL_DECODED)
306 BEGIN_BPF_CMD_DECODER(BPF_PROG_TEST_RUN)
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);
318 END_BPF_CMD_DECODER(RVAL_DECODED)
320 BEGIN_BPF_CMD_DECODER(BPF_PROG_GET_NEXT_ID)
322 PRINT_FIELD_U("{", attr, start_id);
323 PRINT_FIELD_U(", ", attr, next_id);
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))
328 PRINT_FIELD_FLAGS(", ", attr, open_flags, bpf_file_mode_flags,
331 END_BPF_CMD_DECODER(RVAL_DECODED)
333 #define decode_BPF_MAP_GET_NEXT_ID decode_BPF_PROG_GET_NEXT_ID
335 BEGIN_BPF_CMD_DECODER(BPF_PROG_GET_FD_BY_ID)
337 PRINT_FIELD_U("{", attr, prog_id);
338 PRINT_FIELD_U(", ", attr, next_id);
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))
343 PRINT_FIELD_FLAGS(", ", attr, open_flags, bpf_file_mode_flags,
346 END_BPF_CMD_DECODER(RVAL_DECODED)
348 BEGIN_BPF_CMD_DECODER(BPF_MAP_GET_FD_BY_ID)
350 PRINT_FIELD_U("{", attr, map_id);
351 PRINT_FIELD_U(", ", attr, next_id);
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))
356 PRINT_FIELD_FLAGS(", ", attr, open_flags, bpf_file_mode_flags,
359 END_BPF_CMD_DECODER(RVAL_DECODED)
361 BEGIN_BPF_CMD_DECODER(BPF_OBJ_GET_INFO_BY_FD)
363 PRINT_FIELD_FD("{info={", attr, bpf_fd, tcp);
364 PRINT_FIELD_U(", ", attr, info_len);
365 PRINT_FIELD_X(", ", attr, info);
368 END_BPF_CMD_DECODER(RVAL_DECODED | RVAL_FD)
370 BEGIN_BPF_CMD_DECODER(BPF_PROG_QUERY)
372 uint64_t prog_id_buf;
375 PRINT_FIELD_FD("{query={", attr, target_fd, tcp);
376 PRINT_FIELD_XVAL(", ", attr, attach_type, bpf_attach_type,
378 PRINT_FIELD_FLAGS(", ", attr, query_flags, bpf_query_flags,
380 PRINT_FIELD_FLAGS(", ", attr, attach_flags, bpf_attach_flags,
383 tprints(", prog_ids=");
386 priv = xcalloc(1, sizeof(*priv));
388 priv->bpf_prog_query_stored = true;
389 priv->bpf_prog_query_prog_cnt = attr.prog_cnt;
391 set_tcb_priv_data(tcp, priv, free);
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
401 if (syserror(tcp) || attr.prog_ids > max_kaddr())
402 printaddr64(attr.prog_ids);
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);
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);
415 END_BPF_CMD_DECODER(RVAL_DECODED)
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),
440 struct bpf_priv_data *priv = NULL;
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;
448 buf = xmalloc(get_pagesize());
451 printxval(bpf_commands, cmd, "BPF_???");
454 priv = get_tcb_priv_data(tcp);
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);
467 if (exiting(tcp) || (rc & RVAL_DECODED))
468 tprintf(", %u", size);