/src/capstonev5/arch/BPF/BPFDisassembler.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Capstone Disassembly Engine */ |
2 | | /* BPF Backend by david942j <david942j@gmail.com>, 2019 */ |
3 | | |
4 | | #ifdef CAPSTONE_HAS_BPF |
5 | | |
6 | | #include <string.h> |
7 | | #include <stddef.h> // offsetof macro |
8 | | |
9 | | #include "BPFConstants.h" |
10 | | #include "BPFDisassembler.h" |
11 | | #include "BPFMapping.h" |
12 | | #include "../../cs_priv.h" |
13 | | |
14 | | static uint16_t read_u16(cs_struct *ud, const uint8_t *code) |
15 | 17.1k | { |
16 | 17.1k | if (MODE_IS_BIG_ENDIAN(ud->mode)) |
17 | 8.39k | return (((uint16_t)code[0] << 8) | code[1]); |
18 | 8.77k | else |
19 | 8.77k | return (((uint16_t)code[1] << 8) | code[0]); |
20 | 17.1k | } |
21 | | |
22 | | static uint32_t read_u32(cs_struct *ud, const uint8_t *code) |
23 | 5.92k | { |
24 | 5.92k | if (MODE_IS_BIG_ENDIAN(ud->mode)) |
25 | 2.97k | return ((uint32_t)read_u16(ud, code) << 16) | read_u16(ud, code + 2); |
26 | 2.95k | else |
27 | 2.95k | return ((uint32_t)read_u16(ud, code + 2) << 16) | read_u16(ud, code); |
28 | 5.92k | } |
29 | | |
30 | | ///< Malloc bpf_internal, also checks if code_len is large enough. |
31 | | static bpf_internal *alloc_bpf_internal(size_t code_len) |
32 | 5.71k | { |
33 | 5.71k | bpf_internal *bpf; |
34 | | |
35 | 5.71k | if (code_len < 8) |
36 | 91 | return NULL; |
37 | 5.62k | bpf = cs_mem_malloc(sizeof(bpf_internal)); |
38 | 5.62k | if (bpf == NULL) |
39 | 0 | return NULL; |
40 | | /* default value */ |
41 | 5.62k | bpf->insn_size = 8; |
42 | 5.62k | return bpf; |
43 | 5.62k | } |
44 | | |
45 | | ///< Fetch a cBPF structure from code |
46 | | static bpf_internal* fetch_cbpf(cs_struct *ud, const uint8_t *code, |
47 | | size_t code_len) |
48 | 2.07k | { |
49 | 2.07k | bpf_internal *bpf; |
50 | | |
51 | 2.07k | bpf = alloc_bpf_internal(code_len); |
52 | 2.07k | if (bpf == NULL) |
53 | 30 | return NULL; |
54 | | |
55 | 2.04k | bpf->op = read_u16(ud, code); |
56 | 2.04k | bpf->jt = code[2]; |
57 | 2.04k | bpf->jf = code[3]; |
58 | 2.04k | bpf->k = read_u32(ud, code + 4); |
59 | 2.04k | return bpf; |
60 | 2.07k | } |
61 | | |
62 | | ///< Fetch an eBPF structure from code |
63 | | static bpf_internal* fetch_ebpf(cs_struct *ud, const uint8_t *code, |
64 | | size_t code_len) |
65 | 3.63k | { |
66 | 3.63k | bpf_internal *bpf; |
67 | | |
68 | 3.63k | bpf = alloc_bpf_internal(code_len); |
69 | 3.63k | if (bpf == NULL) |
70 | 61 | return NULL; |
71 | | |
72 | 3.57k | bpf->op = (uint16_t)code[0]; |
73 | 3.57k | bpf->dst = code[1] & 0xf; |
74 | 3.57k | bpf->src = (code[1] & 0xf0) >> 4; |
75 | | |
76 | | // eBPF has one 16-byte instruction: BPF_LD | BPF_DW | BPF_IMM, |
77 | | // in this case imm is combined with the next block's imm. |
78 | 3.57k | if (bpf->op == (BPF_CLASS_LD | BPF_SIZE_DW | BPF_MODE_IMM)) { |
79 | 305 | if (code_len < 16) { |
80 | 1 | cs_mem_free(bpf); |
81 | 1 | return NULL; |
82 | 1 | } |
83 | 304 | bpf->k = read_u32(ud, code + 4) | (((uint64_t)read_u32(ud, code + 12)) << 32); |
84 | 304 | bpf->insn_size = 16; |
85 | 304 | } |
86 | 3.27k | else { |
87 | 3.27k | bpf->offset = read_u16(ud, code + 2); |
88 | 3.27k | bpf->k = read_u32(ud, code + 4); |
89 | 3.27k | } |
90 | 3.57k | return bpf; |
91 | 3.57k | } |
92 | | |
93 | 1.55k | #define CHECK_READABLE_REG(ud, reg) do { \ |
94 | 1.55k | if (! ((reg) >= BPF_REG_R0 && (reg) <= BPF_REG_R10)) \ |
95 | 1.55k | return false; \ |
96 | 1.55k | } while (0) |
97 | | |
98 | 1.79k | #define CHECK_WRITABLE_REG(ud, reg) do { \ |
99 | 1.79k | if (! ((reg) >= BPF_REG_R0 && (reg) < BPF_REG_R10)) \ |
100 | 1.79k | return false; \ |
101 | 1.79k | } while (0) |
102 | | |
103 | 1.55k | #define CHECK_READABLE_AND_PUSH(ud, MI, r) do { \ |
104 | 1.55k | CHECK_READABLE_REG(ud, r + BPF_REG_R0); \ |
105 | 1.55k | MCOperand_CreateReg0(MI, r + BPF_REG_R0); \ |
106 | 1.53k | } while (0) |
107 | | |
108 | 1.79k | #define CHECK_WRITABLE_AND_PUSH(ud, MI, r) do { \ |
109 | 1.79k | CHECK_WRITABLE_REG(ud, r + BPF_REG_R0); \ |
110 | 1.79k | MCOperand_CreateReg0(MI, r + BPF_REG_R0); \ |
111 | 1.78k | } while (0) |
112 | | |
113 | | static bool decodeLoad(cs_struct *ud, MCInst *MI, bpf_internal *bpf) |
114 | 1.58k | { |
115 | 1.58k | if (!EBPF_MODE(ud)) { |
116 | | /* |
117 | | * +-----+-----------+--------------------+ |
118 | | * | ldb | [k] | [x+k] | |
119 | | * | ldh | [k] | [x+k] | |
120 | | * +-----+-----------+--------------------+ |
121 | | */ |
122 | 862 | if (BPF_SIZE(bpf->op) == BPF_SIZE_DW) |
123 | 4 | return false; |
124 | 858 | if (BPF_SIZE(bpf->op) == BPF_SIZE_B || BPF_SIZE(bpf->op) == BPF_SIZE_H) { |
125 | | /* no ldx */ |
126 | 145 | if (BPF_CLASS(bpf->op) != BPF_CLASS_LD) |
127 | 3 | return false; |
128 | | /* can only be BPF_ABS and BPF_IND */ |
129 | 142 | if (BPF_MODE(bpf->op) == BPF_MODE_ABS) { |
130 | 75 | MCOperand_CreateImm0(MI, bpf->k); |
131 | 75 | return true; |
132 | 75 | } |
133 | 67 | else if (BPF_MODE(bpf->op) == BPF_MODE_IND) { |
134 | 66 | MCOperand_CreateReg0(MI, BPF_REG_X); |
135 | 66 | MCOperand_CreateImm0(MI, bpf->k); |
136 | 66 | return true; |
137 | 66 | } |
138 | 1 | return false; |
139 | 142 | } |
140 | | /* |
141 | | * +-----+----+------+------+-----+-------+ |
142 | | * | ld | #k | #len | M[k] | [k] | [x+k] | |
143 | | * +-----+----+------+------+-----+-------+ |
144 | | * | ldx | #k | #len | M[k] | 4*([k]&0xf) | |
145 | | * +-----+----+------+------+-------------+ |
146 | | */ |
147 | 713 | switch (BPF_MODE(bpf->op)) { |
148 | 195 | default: |
149 | 195 | break; |
150 | 315 | case BPF_MODE_IMM: |
151 | 315 | MCOperand_CreateImm0(MI, bpf->k); |
152 | 315 | return true; |
153 | 151 | case BPF_MODE_LEN: |
154 | 151 | return true; |
155 | 52 | case BPF_MODE_MEM: |
156 | 52 | MCOperand_CreateImm0(MI, bpf->k); |
157 | 52 | return true; |
158 | 713 | } |
159 | 195 | if (BPF_CLASS(bpf->op) == BPF_CLASS_LD) { |
160 | 171 | if (BPF_MODE(bpf->op) == BPF_MODE_ABS) { |
161 | 71 | MCOperand_CreateImm0(MI, bpf->k); |
162 | 71 | return true; |
163 | 71 | } |
164 | 100 | else if (BPF_MODE(bpf->op) == BPF_MODE_IND) { |
165 | 99 | MCOperand_CreateReg0(MI, BPF_REG_X); |
166 | 99 | MCOperand_CreateImm0(MI, bpf->k); |
167 | 99 | return true; |
168 | 99 | } |
169 | 171 | } |
170 | 24 | else { /* LDX */ |
171 | 24 | if (BPF_MODE(bpf->op) == BPF_MODE_MSH) { |
172 | 22 | MCOperand_CreateImm0(MI, bpf->k); |
173 | 22 | return true; |
174 | 22 | } |
175 | 24 | } |
176 | 3 | return false; |
177 | 195 | } |
178 | | |
179 | | /* eBPF mode */ |
180 | | /* |
181 | | * - IMM: lddw dst, imm64 |
182 | | * - ABS: ld{w,h,b,dw} [k] |
183 | | * - IND: ld{w,h,b,dw} [src+k] |
184 | | * - MEM: ldx{w,h,b,dw} dst, [src+off] |
185 | | */ |
186 | 727 | if (BPF_CLASS(bpf->op) == BPF_CLASS_LD) { |
187 | 579 | switch (BPF_MODE(bpf->op)) { |
188 | 311 | case BPF_MODE_IMM: |
189 | 311 | if (bpf->op != (BPF_CLASS_LD | BPF_SIZE_DW | BPF_MODE_IMM)) |
190 | 7 | return false; |
191 | 304 | CHECK_WRITABLE_AND_PUSH(ud, MI, bpf->dst); |
192 | 302 | MCOperand_CreateImm0(MI, bpf->k); |
193 | 302 | return true; |
194 | 207 | case BPF_MODE_ABS: |
195 | 207 | MCOperand_CreateImm0(MI, bpf->k); |
196 | 207 | return true; |
197 | 58 | case BPF_MODE_IND: |
198 | 58 | CHECK_READABLE_AND_PUSH(ud, MI, bpf->src); |
199 | 57 | MCOperand_CreateImm0(MI, bpf->k); |
200 | 57 | return true; |
201 | 579 | } |
202 | 3 | return false; |
203 | | |
204 | 579 | } |
205 | | /* LDX */ |
206 | 148 | if (BPF_MODE(bpf->op) == BPF_MODE_MEM) { |
207 | 140 | CHECK_WRITABLE_AND_PUSH(ud, MI, bpf->dst); |
208 | 138 | CHECK_READABLE_AND_PUSH(ud, MI, bpf->src); |
209 | 138 | MCOperand_CreateImm0(MI, bpf->offset); |
210 | 138 | return true; |
211 | 138 | } |
212 | 8 | return false; |
213 | 148 | } |
214 | | |
215 | | static bool decodeStore(cs_struct *ud, MCInst *MI, bpf_internal *bpf) |
216 | 545 | { |
217 | | /* in cBPF, only BPF_ST* | BPF_MEM | BPF_W is valid |
218 | | * while in eBPF: |
219 | | * - BPF_STX | BPF_XADD | BPF_{W,DW} |
220 | | * - BPF_ST* | BPF_MEM | BPF_{W,H,B,DW} |
221 | | * are valid |
222 | | */ |
223 | 545 | if (!EBPF_MODE(ud)) { |
224 | | /* can only store to M[] */ |
225 | 19 | if (bpf->op != (BPF_CLASS(bpf->op) | BPF_MODE_MEM | BPF_SIZE_W)) |
226 | 8 | return false; |
227 | 11 | MCOperand_CreateImm0(MI, bpf->k); |
228 | 11 | return true; |
229 | 19 | } |
230 | | |
231 | | /* eBPF */ |
232 | | |
233 | 526 | if (BPF_MODE(bpf->op) == BPF_MODE_XADD) { |
234 | 48 | if (BPF_CLASS(bpf->op) != BPF_CLASS_STX) |
235 | 0 | return false; |
236 | 48 | if (BPF_SIZE(bpf->op) != BPF_SIZE_W && BPF_SIZE(bpf->op) != BPF_SIZE_DW) |
237 | 0 | return false; |
238 | | /* xadd [dst + off], src */ |
239 | 48 | CHECK_READABLE_AND_PUSH(ud, MI, bpf->dst); |
240 | 48 | MCOperand_CreateImm0(MI, bpf->offset); |
241 | 48 | CHECK_READABLE_AND_PUSH(ud, MI, bpf->src); |
242 | 48 | return true; |
243 | 48 | } |
244 | | |
245 | 478 | if (BPF_MODE(bpf->op) != BPF_MODE_MEM) |
246 | 7 | return false; |
247 | | |
248 | | /* st [dst + off], src */ |
249 | 471 | CHECK_READABLE_AND_PUSH(ud, MI, bpf->dst); |
250 | 471 | MCOperand_CreateImm0(MI, bpf->offset); |
251 | 471 | if (BPF_CLASS(bpf->op) == BPF_CLASS_ST) |
252 | 277 | MCOperand_CreateImm0(MI, bpf->k); |
253 | 194 | else |
254 | 194 | CHECK_READABLE_AND_PUSH(ud, MI, bpf->src); |
255 | 471 | return true; |
256 | 471 | } |
257 | | |
258 | | static bool decodeALU(cs_struct *ud, MCInst *MI, bpf_internal *bpf) |
259 | 1.88k | { |
260 | | /* Set MI->Operands */ |
261 | | |
262 | | /* cBPF */ |
263 | 1.88k | if (!EBPF_MODE(ud)) { |
264 | 516 | if (BPF_OP(bpf->op) > BPF_ALU_XOR) |
265 | 3 | return false; |
266 | | /* cBPF's NEG has no operands */ |
267 | 513 | if (BPF_OP(bpf->op) == BPF_ALU_NEG) |
268 | 149 | return true; |
269 | 364 | if (BPF_SRC(bpf->op) == BPF_SRC_K) |
270 | 163 | MCOperand_CreateImm0(MI, bpf->k); |
271 | 201 | else /* BPF_SRC_X */ |
272 | 201 | MCOperand_CreateReg0(MI, BPF_REG_X); |
273 | 364 | return true; |
274 | 513 | } |
275 | | |
276 | | /* eBPF */ |
277 | | |
278 | 1.36k | if (BPF_OP(bpf->op) > BPF_ALU_END) |
279 | 6 | return false; |
280 | | /* ALU64 class doesn't have ENDian */ |
281 | | /* ENDian's imm must be one of 16, 32, 64 */ |
282 | 1.36k | if (BPF_OP(bpf->op) == BPF_ALU_END) { |
283 | 49 | if (BPF_CLASS(bpf->op) == BPF_CLASS_ALU64) |
284 | 2 | return false; |
285 | 47 | if (bpf->k != 16 && bpf->k != 32 && bpf->k != 64) |
286 | 11 | return false; |
287 | 47 | } |
288 | | |
289 | | /* - op dst, imm |
290 | | * - op dst, src |
291 | | * - neg dst |
292 | | * - le<imm> dst |
293 | | */ |
294 | | /* every ALU instructions have dst op */ |
295 | 1.34k | CHECK_WRITABLE_AND_PUSH(ud, MI, bpf->dst); |
296 | | |
297 | | /* special cases */ |
298 | 1.34k | if (BPF_OP(bpf->op) == BPF_ALU_NEG) |
299 | 268 | return true; |
300 | 1.07k | if (BPF_OP(bpf->op) == BPF_ALU_END) { |
301 | | /* bpf->k must be one of 16, 32, 64 */ |
302 | 36 | MCInst_setOpcode(MI, MCInst_getOpcode(MI) | ((uint32_t)bpf->k << 4)); |
303 | 36 | return true; |
304 | 36 | } |
305 | | |
306 | | /* normal cases */ |
307 | 1.03k | if (BPF_SRC(bpf->op) == BPF_SRC_K) { |
308 | 923 | MCOperand_CreateImm0(MI, bpf->k); |
309 | 923 | } |
310 | 114 | else { /* BPF_SRC_X */ |
311 | 114 | CHECK_READABLE_AND_PUSH(ud, MI, bpf->src); |
312 | 114 | } |
313 | 1.03k | return true; |
314 | 1.03k | } |
315 | | |
316 | | static bool decodeJump(cs_struct *ud, MCInst *MI, bpf_internal *bpf) |
317 | 1.30k | { |
318 | | /* cBPF and eBPF are very different in class jump */ |
319 | 1.30k | if (!EBPF_MODE(ud)) { |
320 | 352 | if (BPF_OP(bpf->op) > BPF_JUMP_JSET) |
321 | 3 | return false; |
322 | | |
323 | | /* ja is a special case of jumps */ |
324 | 349 | if (BPF_OP(bpf->op) == BPF_JUMP_JA) { |
325 | 50 | MCOperand_CreateImm0(MI, bpf->k); |
326 | 50 | return true; |
327 | 50 | } |
328 | | |
329 | 299 | if (BPF_SRC(bpf->op) == BPF_SRC_K) |
330 | 160 | MCOperand_CreateImm0(MI, bpf->k); |
331 | 139 | else /* BPF_SRC_X */ |
332 | 139 | MCOperand_CreateReg0(MI, BPF_REG_X); |
333 | 299 | MCOperand_CreateImm0(MI, bpf->jt); |
334 | 299 | MCOperand_CreateImm0(MI, bpf->jf); |
335 | 299 | } |
336 | 951 | else { |
337 | 951 | if (BPF_OP(bpf->op) > BPF_JUMP_JSLE) |
338 | 0 | return false; |
339 | | |
340 | | /* No operands for exit */ |
341 | 951 | if (BPF_OP(bpf->op) == BPF_JUMP_EXIT) |
342 | 274 | return bpf->op == (BPF_CLASS_JMP | BPF_JUMP_EXIT); |
343 | 677 | if (BPF_OP(bpf->op) == BPF_JUMP_CALL) { |
344 | 127 | if (bpf->op == (BPF_CLASS_JMP | BPF_JUMP_CALL)) { |
345 | 107 | MCOperand_CreateImm0(MI, bpf->k); |
346 | 107 | return true; |
347 | 107 | } |
348 | 20 | if (bpf->op == (BPF_CLASS_JMP | BPF_JUMP_CALL | BPF_SRC_X)) { |
349 | 20 | CHECK_READABLE_AND_PUSH(ud, MI, bpf->k); |
350 | 5 | return true; |
351 | 20 | } |
352 | 0 | return false; |
353 | 20 | } |
354 | | |
355 | | /* ja is a special case of jumps */ |
356 | 550 | if (BPF_OP(bpf->op) == BPF_JUMP_JA) { |
357 | 139 | if (BPF_SRC(bpf->op) != BPF_SRC_K) |
358 | 1 | return false; |
359 | 138 | MCOperand_CreateImm0(MI, bpf->offset); |
360 | 138 | return true; |
361 | 139 | } |
362 | | |
363 | | /* <j> dst, src, +off */ |
364 | 411 | CHECK_READABLE_AND_PUSH(ud, MI, bpf->dst); |
365 | 408 | if (BPF_SRC(bpf->op) == BPF_SRC_K) |
366 | 355 | MCOperand_CreateImm0(MI, bpf->k); |
367 | 53 | else |
368 | 53 | CHECK_READABLE_AND_PUSH(ud, MI, bpf->src); |
369 | 408 | MCOperand_CreateImm0(MI, bpf->offset); |
370 | 408 | } |
371 | 707 | return true; |
372 | 1.30k | } |
373 | | |
374 | | static bool decodeReturn(cs_struct *ud, MCInst *MI, bpf_internal *bpf) |
375 | 265 | { |
376 | | /* Here only handles the BPF_RET class in cBPF */ |
377 | 265 | switch (BPF_RVAL(bpf->op)) { |
378 | 62 | case BPF_SRC_K: |
379 | 62 | MCOperand_CreateImm0(MI, bpf->k); |
380 | 62 | return true; |
381 | 145 | case BPF_SRC_X: |
382 | 145 | MCOperand_CreateReg0(MI, BPF_REG_X); |
383 | 145 | return true; |
384 | 56 | case BPF_SRC_A: |
385 | 56 | MCOperand_CreateReg0(MI, BPF_REG_A); |
386 | 56 | return true; |
387 | 265 | } |
388 | 2 | return false; |
389 | 265 | } |
390 | | |
391 | | static bool decodeMISC(cs_struct *ud, MCInst *MI, bpf_internal *bpf) |
392 | 32 | { |
393 | 32 | uint16_t op = bpf->op ^ BPF_CLASS_MISC; |
394 | 32 | return op == BPF_MISCOP_TAX || op == BPF_MISCOP_TXA; |
395 | 32 | } |
396 | | |
397 | | ///< 1. Check if the instruction is valid |
398 | | ///< 2. Set MI->opcode |
399 | | ///< 3. Set MI->Operands |
400 | | static bool getInstruction(cs_struct *ud, MCInst *MI, bpf_internal *bpf) |
401 | 5.62k | { |
402 | 5.62k | cs_detail *detail; |
403 | | |
404 | 5.62k | detail = MI->flat_insn->detail; |
405 | | // initialize detail |
406 | 5.62k | if (detail) { |
407 | 5.62k | memset(detail, 0, offsetof(cs_detail, bpf) + sizeof(cs_bpf)); |
408 | 5.62k | } |
409 | | |
410 | 5.62k | MCInst_clear(MI); |
411 | 5.62k | MCInst_setOpcode(MI, bpf->op); |
412 | | |
413 | 5.62k | switch (BPF_CLASS(bpf->op)) { |
414 | 0 | default: /* should never happen */ |
415 | 0 | return false; |
416 | 1.33k | case BPF_CLASS_LD: |
417 | 1.58k | case BPF_CLASS_LDX: |
418 | 1.58k | return decodeLoad(ud, MI, bpf); |
419 | 285 | case BPF_CLASS_ST: |
420 | 545 | case BPF_CLASS_STX: |
421 | 545 | return decodeStore(ud, MI, bpf); |
422 | 1.06k | case BPF_CLASS_ALU: |
423 | 1.06k | return decodeALU(ud, MI, bpf); |
424 | 1.30k | case BPF_CLASS_JMP: |
425 | 1.30k | return decodeJump(ud, MI, bpf); |
426 | 271 | case BPF_CLASS_RET: |
427 | | /* eBPF doesn't have this class */ |
428 | 271 | if (EBPF_MODE(ud)) |
429 | 6 | return false; |
430 | 265 | return decodeReturn(ud, MI, bpf); |
431 | 850 | case BPF_CLASS_MISC: |
432 | | /* case BPF_CLASS_ALU64: */ |
433 | 850 | if (EBPF_MODE(ud)) |
434 | 818 | return decodeALU(ud, MI, bpf); |
435 | 32 | else |
436 | 32 | return decodeMISC(ud, MI, bpf); |
437 | 5.62k | } |
438 | 5.62k | } |
439 | | |
440 | | bool BPF_getInstruction(csh ud, const uint8_t *code, size_t code_len, |
441 | | MCInst *instr, uint16_t *size, uint64_t address, void *info) |
442 | 5.71k | { |
443 | 5.71k | cs_struct *cs; |
444 | 5.71k | bpf_internal *bpf; |
445 | | |
446 | 5.71k | cs = (cs_struct*)ud; |
447 | 5.71k | if (EBPF_MODE(cs)) |
448 | 3.63k | bpf = fetch_ebpf(cs, code, code_len); |
449 | 2.07k | else |
450 | 2.07k | bpf = fetch_cbpf(cs, code, code_len); |
451 | 5.71k | if (bpf == NULL) |
452 | 92 | return false; |
453 | 5.62k | if (!getInstruction(cs, instr, bpf)) { |
454 | 120 | cs_mem_free(bpf); |
455 | 120 | return false; |
456 | 120 | } |
457 | | |
458 | 5.50k | *size = bpf->insn_size; |
459 | 5.50k | cs_mem_free(bpf); |
460 | | |
461 | 5.50k | return true; |
462 | 5.62k | } |
463 | | |
464 | | #endif |