Mirror of strace – the linux syscall tracer
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

bpf_filter.c 3.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. /*
  2. * Decoder of classic BPF programs.
  3. *
  4. * Copyright (c) 2015-2017 Dmitry V. Levin <ldv@altlinux.org>
  5. * Copyright (c) 2017-2018 The strace developers.
  6. * All rights reserved.
  7. *
  8. * SPDX-License-Identifier: LGPL-2.1-or-later
  9. */
  10. #include "defs.h"
  11. #include "bpf_filter.h"
  12. #include "bpf_fprog.h"
  13. #include <linux/filter.h>
  14. #include "xlat/bpf_class.h"
  15. #include "xlat/bpf_miscop.h"
  16. #include "xlat/bpf_mode.h"
  17. #include "xlat/bpf_op_alu.h"
  18. #include "xlat/bpf_op_jmp.h"
  19. #include "xlat/bpf_rval.h"
  20. #include "xlat/bpf_size.h"
  21. #include "xlat/bpf_src.h"
  22. #include "xlat/ebpf_class.h"
  23. #include "xlat/ebpf_mode.h"
  24. #include "xlat/ebpf_op_alu.h"
  25. #include "xlat/ebpf_op_jmp.h"
  26. #include "xlat/ebpf_size.h"
  27. void
  28. print_bpf_filter_code(const uint16_t code, bool extended)
  29. {
  30. const struct xlat *mode = extended ? ebpf_mode : bpf_mode;
  31. uint16_t i = code & ~BPF_CLASS(code);
  32. printxval(extended ? ebpf_class : bpf_class, BPF_CLASS(code),
  33. "BPF_???");
  34. switch (BPF_CLASS(code)) {
  35. case BPF_ST:
  36. case BPF_STX:
  37. if (!extended) {
  38. if (i) {
  39. tprintf("|%#x", i);
  40. tprints_comment("BPF_???");
  41. }
  42. break;
  43. }
  44. ATTRIBUTE_FALLTHROUGH; /* extended == true */
  45. case BPF_LD:
  46. case BPF_LDX:
  47. tprints("|");
  48. printxvals(BPF_SIZE(code), "BPF_???",
  49. bpf_size, extended ? ebpf_size : NULL, NULL);
  50. tprints("|");
  51. printxval(mode, BPF_MODE(code), "BPF_???");
  52. break;
  53. case BPF_MISC: /* BPF_ALU64 in eBPF */
  54. if (!extended) {
  55. tprints("|");
  56. printxval(bpf_miscop, BPF_MISCOP(code), "BPF_???");
  57. i &= ~BPF_MISCOP(code);
  58. if (i) {
  59. tprintf("|%#x", i);
  60. tprints_comment("BPF_???");
  61. }
  62. break;
  63. }
  64. ATTRIBUTE_FALLTHROUGH; /* extended == true */
  65. case BPF_ALU:
  66. tprints("|");
  67. printxval(bpf_src, BPF_SRC(code), "BPF_???");
  68. tprints("|");
  69. printxvals(BPF_OP(code), "BPF_???",
  70. bpf_op_alu,
  71. extended ? ebpf_op_alu : NULL, NULL);
  72. break;
  73. case BPF_JMP:
  74. tprints("|");
  75. printxval(bpf_src, BPF_SRC(code), "BPF_???");
  76. tprints("|");
  77. printxvals(BPF_OP(code), "BPF_???",
  78. bpf_op_jmp, extended ? ebpf_op_jmp : NULL, NULL);
  79. break;
  80. case BPF_RET: /* Reserved in eBPF */
  81. if (!extended) {
  82. tprints("|");
  83. printxval(bpf_rval, BPF_RVAL(code), "BPF_???");
  84. i &= ~BPF_RVAL(code);
  85. }
  86. if (i) {
  87. tprintf("|%#x", i);
  88. tprints_comment("BPF_???");
  89. }
  90. break;
  91. }
  92. }
  93. static void
  94. print_bpf_filter_stmt(const struct bpf_filter_block *const filter,
  95. const print_bpf_filter_fn print_k)
  96. {
  97. tprints("BPF_STMT(");
  98. print_bpf_filter_code(filter->code, false);
  99. tprints(", ");
  100. if (!print_k || !print_k(filter))
  101. tprintf("%#x", filter->k);
  102. tprints(")");
  103. }
  104. static void
  105. print_bpf_filter_jump(const struct bpf_filter_block *const filter)
  106. {
  107. tprints("BPF_JUMP(");
  108. print_bpf_filter_code(filter->code, false);
  109. tprintf(", %#x, %#x, %#x)", filter->k, filter->jt, filter->jf);
  110. }
  111. struct bpf_filter_block_data {
  112. const print_bpf_filter_fn fn;
  113. unsigned int count;
  114. };
  115. static bool
  116. print_bpf_filter_block(struct tcb *const tcp, void *const elem_buf,
  117. const size_t elem_size, void *const data)
  118. {
  119. const struct bpf_filter_block *const filter = elem_buf;
  120. struct bpf_filter_block_data *const fbd = data;
  121. if (fbd->count++ >= BPF_MAXINSNS) {
  122. tprints("...");
  123. return false;
  124. }
  125. if (filter->jt || filter->jf)
  126. print_bpf_filter_jump(filter);
  127. else
  128. print_bpf_filter_stmt(filter, fbd->fn);
  129. return true;
  130. }
  131. void
  132. print_bpf_fprog(struct tcb *const tcp, const kernel_ulong_t addr,
  133. const unsigned short len, const print_bpf_filter_fn print_k)
  134. {
  135. if (abbrev(tcp)) {
  136. printaddr(addr);
  137. } else {
  138. struct bpf_filter_block_data fbd = { .fn = print_k };
  139. struct bpf_filter_block filter;
  140. print_array(tcp, addr, len, &filter, sizeof(filter),
  141. tfetch_mem, print_bpf_filter_block, &fbd);
  142. }
  143. }
  144. void
  145. decode_bpf_fprog(struct tcb *const tcp, const kernel_ulong_t addr,
  146. const print_bpf_filter_fn print_k)
  147. {
  148. struct bpf_fprog fprog;
  149. if (fetch_bpf_fprog(tcp, addr, &fprog)) {
  150. tprintf("{len=%hu, filter=", fprog.len);
  151. print_bpf_fprog(tcp, fprog.filter, fprog.len, print_k);
  152. tprints("}");
  153. }
  154. }