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