Coverage Report

Created: 2026-03-11 06:06

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/capstonev5/arch/BPF/BPFDisassembler.c
Line
Count
Source
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
42.7k
{
16
42.7k
  if (MODE_IS_BIG_ENDIAN(ud->mode))
17
19.3k
    return (((uint16_t)code[0] << 8) | code[1]);
18
23.3k
  else
19
23.3k
    return (((uint16_t)code[1] << 8) | code[0]);
20
42.7k
}
21
22
static uint32_t read_u32(cs_struct *ud, const uint8_t *code)
23
14.3k
{
24
14.3k
  if (MODE_IS_BIG_ENDIAN(ud->mode))
25
6.46k
    return ((uint32_t)read_u16(ud, code) << 16) | read_u16(ud, code + 2);
26
7.91k
  else
27
7.91k
    return ((uint32_t)read_u16(ud, code + 2) << 16) | read_u16(ud, code);
28
14.3k
}
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
30.1k
{
33
30.1k
  bpf_internal *bpf;
34
35
30.1k
  if (code_len < 8)
36
461
    return NULL;
37
29.7k
  bpf = cs_mem_malloc(sizeof(bpf_internal));
38
29.7k
  if (bpf == NULL)
39
0
    return NULL;
40
  /* default value */
41
29.7k
  bpf->insn_size = 8;
42
29.7k
  return bpf;
43
29.7k
}
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
11.9k
{
49
11.9k
  bpf_internal *bpf;
50
51
11.9k
  bpf = alloc_bpf_internal(code_len);
52
11.9k
  if (bpf == NULL)
53
172
    return NULL;
54
55
11.7k
  bpf->op = read_u16(ud, code);
56
11.7k
  bpf->jt = code[2];
57
11.7k
  bpf->jf = code[3];
58
11.7k
  bpf->k = read_u32(ud, code + 4);
59
11.7k
  return bpf;
60
11.9k
}
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
18.2k
{
66
18.2k
  bpf_internal *bpf;
67
68
18.2k
  bpf = alloc_bpf_internal(code_len);
69
18.2k
  if (bpf == NULL)
70
289
    return NULL;
71
72
17.9k
  bpf->op = (uint16_t)code[0];
73
17.9k
  bpf->dst = code[1] & 0xf;
74
17.9k
  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
17.9k
  if (bpf->op == (BPF_CLASS_LD | BPF_SIZE_DW | BPF_MODE_IMM)) {
79
280
    if (code_len < 16) {
80
5
      cs_mem_free(bpf);
81
5
      return NULL;
82
5
    }
83
275
    bpf->k = read_u32(ud, code + 4) | (((uint64_t)read_u32(ud, code + 12)) << 32);
84
275
    bpf->insn_size = 16;
85
275
  }
86
17.7k
  else {
87
17.7k
    bpf->offset = read_u16(ud, code + 2);
88
17.7k
    bpf->k = read_u32(ud, code + 4);
89
17.7k
  }
90
17.9k
  return bpf;
91
17.9k
}
92
93
6.37k
#define CHECK_READABLE_REG(ud, reg) do { \
94
6.37k
    if (! ((reg) >= BPF_REG_R0 && (reg) <= BPF_REG_R10)) \
95
6.37k
      return false; \
96
6.37k
  } while (0)
97
98
4.38k
#define CHECK_WRITABLE_REG(ud, reg) do { \
99
4.38k
    if (! ((reg) >= BPF_REG_R0 && (reg) < BPF_REG_R10)) \
100
4.38k
      return false; \
101
4.38k
  } while (0)
102
103
6.37k
#define CHECK_READABLE_AND_PUSH(ud, MI, r) do { \
104
6.37k
    CHECK_READABLE_REG(ud, r + BPF_REG_R0); \
105
6.37k
    MCOperand_CreateReg0(MI, r + BPF_REG_R0); \
106
6.33k
  } while (0)
107
108
4.38k
#define CHECK_WRITABLE_AND_PUSH(ud, MI, r) do { \
109
4.38k
    CHECK_WRITABLE_REG(ud, r + BPF_REG_R0); \
110
4.38k
    MCOperand_CreateReg0(MI, r + BPF_REG_R0); \
111
4.37k
  } while (0)
112
113
static bool decodeLoad(cs_struct *ud, MCInst *MI, bpf_internal *bpf)
114
8.88k
{
115
8.88k
  if (!EBPF_MODE(ud)) {
116
    /*
117
     *  +-----+-----------+--------------------+
118
     *  | ldb |    [k]    |       [x+k]        |
119
     *  | ldh |    [k]    |       [x+k]        |
120
     *  +-----+-----------+--------------------+
121
     */
122
5.20k
    if (BPF_SIZE(bpf->op) == BPF_SIZE_DW)
123
6
      return false;
124
5.20k
    if (BPF_SIZE(bpf->op) == BPF_SIZE_B || BPF_SIZE(bpf->op) == BPF_SIZE_H) {
125
      /* no ldx */
126
1.53k
      if (BPF_CLASS(bpf->op) != BPF_CLASS_LD)
127
8
        return false;
128
      /* can only be BPF_ABS and BPF_IND */
129
1.52k
      if (BPF_MODE(bpf->op) == BPF_MODE_ABS) {
130
620
        MCOperand_CreateImm0(MI, bpf->k);
131
620
        return true;
132
620
      }
133
909
      else if (BPF_MODE(bpf->op) == BPF_MODE_IND) {
134
905
        MCOperand_CreateReg0(MI, BPF_REG_X);
135
905
        MCOperand_CreateImm0(MI, bpf->k);
136
905
        return true;
137
905
      }
138
4
      return false;
139
1.52k
    }
140
    /*
141
     *  +-----+----+------+------+-----+-------+
142
     *  | ld  | #k | #len | M[k] | [k] | [x+k] |
143
     *  +-----+----+------+------+-----+-------+
144
     *  | ldx | #k | #len | M[k] | 4*([k]&0xf) |
145
     *  +-----+----+------+------+-------------+
146
     */
147
3.66k
    switch (BPF_MODE(bpf->op)) {
148
1.66k
    default:
149
1.66k
      break;
150
1.66k
    case BPF_MODE_IMM:
151
1.44k
      MCOperand_CreateImm0(MI, bpf->k);
152
1.44k
      return true;
153
315
    case BPF_MODE_LEN:
154
315
      return true;
155
245
    case BPF_MODE_MEM:
156
245
      MCOperand_CreateImm0(MI, bpf->k);
157
245
      return true;
158
3.66k
    }
159
1.66k
    if (BPF_CLASS(bpf->op) == BPF_CLASS_LD) {
160
1.25k
      if (BPF_MODE(bpf->op) == BPF_MODE_ABS) {
161
393
        MCOperand_CreateImm0(MI, bpf->k);
162
393
        return true;
163
393
      }
164
864
      else if (BPF_MODE(bpf->op) == BPF_MODE_IND) {
165
861
        MCOperand_CreateReg0(MI, BPF_REG_X);
166
861
        MCOperand_CreateImm0(MI, bpf->k);
167
861
        return true;
168
861
      }
169
1.25k
    }
170
403
    else { /* LDX */
171
403
      if (BPF_MODE(bpf->op) == BPF_MODE_MSH) {
172
399
        MCOperand_CreateImm0(MI, bpf->k);
173
399
        return true;
174
399
      }
175
403
    }
176
7
    return false;
177
1.66k
  }
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
3.68k
  if (BPF_CLASS(bpf->op) == BPF_CLASS_LD) {
187
2.50k
    switch (BPF_MODE(bpf->op)) {
188
320
    case BPF_MODE_IMM:
189
320
      if (bpf->op != (BPF_CLASS_LD | BPF_SIZE_DW | BPF_MODE_IMM))
190
45
        return false;
191
275
      CHECK_WRITABLE_AND_PUSH(ud, MI, bpf->dst);
192
275
      MCOperand_CreateImm0(MI, bpf->k);
193
275
      return true;
194
1.50k
    case BPF_MODE_ABS:
195
1.50k
      MCOperand_CreateImm0(MI, bpf->k);
196
1.50k
      return true;
197
666
    case BPF_MODE_IND:
198
666
      CHECK_READABLE_AND_PUSH(ud, MI, bpf->src);
199
663
      MCOperand_CreateImm0(MI, bpf->k);
200
663
      return true;
201
2.50k
    }
202
17
    return false;
203
204
2.50k
  }
205
  /* LDX */
206
1.17k
  if (BPF_MODE(bpf->op) == BPF_MODE_MEM) {
207
1.15k
    CHECK_WRITABLE_AND_PUSH(ud, MI, bpf->dst);
208
1.15k
    CHECK_READABLE_AND_PUSH(ud, MI, bpf->src);
209
1.15k
    MCOperand_CreateImm0(MI, bpf->offset);
210
1.15k
    return true;
211
1.15k
  }
212
21
  return false;
213
1.17k
}
214
215
static bool decodeStore(cs_struct *ud, MCInst *MI, bpf_internal *bpf)
216
2.23k
{
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
2.23k
  if (!EBPF_MODE(ud)) {
224
    /* can only store to M[] */
225
265
    if (bpf->op != (BPF_CLASS(bpf->op) | BPF_MODE_MEM | BPF_SIZE_W))
226
19
      return false;
227
246
    MCOperand_CreateImm0(MI, bpf->k);
228
246
    return true;
229
265
  }
230
231
  /* eBPF */
232
233
1.96k
  if (BPF_MODE(bpf->op) == BPF_MODE_XADD) {
234
251
    if (BPF_CLASS(bpf->op) != BPF_CLASS_STX)
235
2
      return false;
236
249
    if (BPF_SIZE(bpf->op) != BPF_SIZE_W && BPF_SIZE(bpf->op) != BPF_SIZE_DW)
237
4
      return false;
238
    /* xadd [dst + off], src */
239
245
    CHECK_READABLE_AND_PUSH(ud, MI, bpf->dst);
240
244
    MCOperand_CreateImm0(MI, bpf->offset);
241
244
    CHECK_READABLE_AND_PUSH(ud, MI, bpf->src);
242
241
    return true;
243
244
  }
244
245
1.71k
  if (BPF_MODE(bpf->op) != BPF_MODE_MEM)
246
27
    return false;
247
248
  /* st [dst + off], src */
249
1.69k
  CHECK_READABLE_AND_PUSH(ud, MI, bpf->dst);
250
1.68k
  MCOperand_CreateImm0(MI, bpf->offset);
251
1.68k
  if (BPF_CLASS(bpf->op) == BPF_CLASS_ST)
252
927
    MCOperand_CreateImm0(MI, bpf->k);
253
760
  else
254
760
    CHECK_READABLE_AND_PUSH(ud, MI, bpf->src);
255
1.68k
  return true;
256
1.68k
}
257
258
static bool decodeALU(cs_struct *ud, MCInst *MI, bpf_internal *bpf)
259
4.58k
{
260
  /* Set MI->Operands */
261
262
  /* cBPF */
263
4.58k
  if (!EBPF_MODE(ud)) {
264
1.59k
    if (BPF_OP(bpf->op) > BPF_ALU_XOR)
265
1
      return false;
266
    /* cBPF's NEG has no operands */
267
1.59k
    if (BPF_OP(bpf->op) == BPF_ALU_NEG)
268
264
      return true;
269
1.33k
    if (BPF_SRC(bpf->op) == BPF_SRC_K)
270
462
      MCOperand_CreateImm0(MI, bpf->k);
271
870
    else /* BPF_SRC_X */
272
870
      MCOperand_CreateReg0(MI, BPF_REG_X);
273
1.33k
    return true;
274
1.59k
  }
275
276
  /* eBPF */
277
278
2.98k
  if (BPF_OP(bpf->op) > BPF_ALU_END)
279
8
    return false;
280
  /* ALU64 class doesn't have ENDian */
281
  /* ENDian's imm must be one of 16, 32, 64 */
282
2.98k
  if (BPF_OP(bpf->op) == BPF_ALU_END) {
283
280
    if (BPF_CLASS(bpf->op) == BPF_CLASS_ALU64)
284
2
      return false;
285
278
    if (bpf->k != 16 && bpf->k != 32 && bpf->k != 64)
286
25
      return false;
287
278
  }
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
2.95k
  CHECK_WRITABLE_AND_PUSH(ud, MI, bpf->dst);
296
297
  /* special cases */
298
2.94k
  if (BPF_OP(bpf->op) == BPF_ALU_NEG)
299
319
    return true;
300
2.62k
  if (BPF_OP(bpf->op) == BPF_ALU_END) {
301
    /* bpf->k must be one of 16, 32, 64 */
302
253
    MCInst_setOpcode(MI, MCInst_getOpcode(MI) | ((uint32_t)bpf->k << 4));
303
253
    return true;
304
253
  }
305
306
  /* normal cases */
307
2.37k
  if (BPF_SRC(bpf->op) == BPF_SRC_K) {
308
2.13k
    MCOperand_CreateImm0(MI, bpf->k);
309
2.13k
  }
310
245
  else { /* BPF_SRC_X */
311
245
    CHECK_READABLE_AND_PUSH(ud, MI, bpf->src);
312
245
  }
313
2.37k
  return true;
314
2.37k
}
315
316
static bool decodeJump(cs_struct *ud, MCInst *MI, bpf_internal *bpf)
317
3.60k
{
318
  /* cBPF and eBPF are very different in class jump */
319
3.60k
  if (!EBPF_MODE(ud)) {
320
952
    if (BPF_OP(bpf->op) > BPF_JUMP_JSET)
321
5
      return false;
322
323
    /* ja is a special case of jumps */
324
947
    if (BPF_OP(bpf->op) == BPF_JUMP_JA) {
325
223
      MCOperand_CreateImm0(MI, bpf->k);
326
223
      return true;
327
223
    }
328
329
724
    if (BPF_SRC(bpf->op) == BPF_SRC_K)
330
317
      MCOperand_CreateImm0(MI, bpf->k);
331
407
    else /* BPF_SRC_X */
332
407
      MCOperand_CreateReg0(MI, BPF_REG_X);
333
724
    MCOperand_CreateImm0(MI, bpf->jt);
334
724
    MCOperand_CreateImm0(MI, bpf->jf);
335
724
  }
336
2.65k
  else {
337
2.65k
    if (BPF_OP(bpf->op) > BPF_JUMP_JSLE)
338
1
      return false;
339
340
    /* No operands for exit */
341
2.65k
    if (BPF_OP(bpf->op) == BPF_JUMP_EXIT)
342
302
      return bpf->op == (BPF_CLASS_JMP | BPF_JUMP_EXIT);
343
2.35k
    if (BPF_OP(bpf->op) == BPF_JUMP_CALL) {
344
359
      if (bpf->op == (BPF_CLASS_JMP | BPF_JUMP_CALL)) {
345
273
        MCOperand_CreateImm0(MI, bpf->k);
346
273
        return true;
347
273
      }
348
86
      if (bpf->op == (BPF_CLASS_JMP | BPF_JUMP_CALL | BPF_SRC_X)) {
349
86
        CHECK_READABLE_AND_PUSH(ud, MI, bpf->k);
350
60
        return true;
351
86
      }
352
0
      return false;
353
86
    }
354
355
    /* ja is a special case of jumps */
356
1.99k
    if (BPF_OP(bpf->op) == BPF_JUMP_JA) {
357
777
      if (BPF_SRC(bpf->op) != BPF_SRC_K)
358
1
        return false;
359
776
      MCOperand_CreateImm0(MI, bpf->offset);
360
776
      return true;
361
777
    }
362
363
    /* <j>  dst, src, +off */
364
1.21k
    CHECK_READABLE_AND_PUSH(ud, MI, bpf->dst);
365
1.21k
    if (BPF_SRC(bpf->op) == BPF_SRC_K)
366
1.14k
      MCOperand_CreateImm0(MI, bpf->k);
367
74
    else
368
74
      CHECK_READABLE_AND_PUSH(ud, MI, bpf->src);
369
1.21k
    MCOperand_CreateImm0(MI, bpf->offset);
370
1.21k
  }
371
1.93k
  return true;
372
3.60k
}
373
374
static bool decodeReturn(cs_struct *ud, MCInst *MI, bpf_internal *bpf)
375
865
{
376
  /* Here only handles the BPF_RET class in cBPF */
377
865
  switch (BPF_RVAL(bpf->op)) {
378
364
  case BPF_SRC_K:
379
364
    MCOperand_CreateImm0(MI, bpf->k);
380
364
    return true;
381
214
  case BPF_SRC_X:
382
214
    MCOperand_CreateReg0(MI, BPF_REG_X);
383
214
    return true;
384
282
  case BPF_SRC_A:
385
282
    MCOperand_CreateReg0(MI, BPF_REG_A);
386
282
    return true;
387
865
  }
388
5
  return false;
389
865
}
390
391
static bool decodeMISC(cs_struct *ud, MCInst *MI, bpf_internal *bpf)
392
400
{
393
400
  uint16_t op = bpf->op ^ BPF_CLASS_MISC;
394
400
  return op == BPF_MISCOP_TAX || op == BPF_MISCOP_TXA;
395
400
}
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
14.1k
{
402
14.1k
  cs_detail *detail;
403
404
14.1k
  detail = MI->flat_insn->detail;
405
  // initialize detail
406
14.1k
  if (detail) {
407
14.1k
    memset(detail, 0, offsetof(cs_detail, bpf) + sizeof(cs_bpf));
408
14.1k
  }
409
410
14.1k
  MCInst_clear(MI);
411
14.1k
  MCInst_setOpcode(MI, bpf->op);
412
413
14.1k
  switch (BPF_CLASS(bpf->op)) {
414
0
  default: /* should never happen */
415
0
    return false;
416
3.45k
  case BPF_CLASS_LD:
417
4.04k
  case BPF_CLASS_LDX:
418
4.04k
    return decodeLoad(ud, MI, bpf);
419
567
  case BPF_CLASS_ST:
420
1.22k
  case BPF_CLASS_STX:
421
1.22k
    return decodeStore(ud, MI, bpf);
422
2.82k
  case BPF_CLASS_ALU:
423
2.82k
    return decodeALU(ud, MI, bpf);
424
3.60k
  case BPF_CLASS_JMP:
425
3.60k
    return decodeJump(ud, MI, bpf);
426
400
  case BPF_CLASS_RET:
427
    /* eBPF doesn't have this class */
428
400
    if (EBPF_MODE(ud))
429
7
      return false;
430
393
    return decodeReturn(ud, MI, bpf);
431
2.05k
  case BPF_CLASS_MISC:
432
  /* case BPF_CLASS_ALU64: */
433
2.05k
    if (EBPF_MODE(ud))
434
1.75k
      return decodeALU(ud, MI, bpf);
435
301
    else
436
301
      return decodeMISC(ud, MI, bpf);
437
14.1k
  }
438
14.1k
}
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
14.3k
{
443
14.3k
  cs_struct *cs;
444
14.3k
  bpf_internal *bpf;
445
446
14.3k
  cs = (cs_struct*)ud;
447
14.3k
  if (EBPF_MODE(cs))
448
8.24k
    bpf = fetch_ebpf(cs, code, code_len);
449
6.11k
  else
450
6.11k
    bpf = fetch_cbpf(cs, code, code_len);
451
14.3k
  if (bpf == NULL)
452
187
    return false;
453
14.1k
  if (!getInstruction(cs, instr, bpf)) {
454
164
    cs_mem_free(bpf);
455
164
    return false;
456
164
  }
457
458
14.0k
  *size = bpf->insn_size;
459
14.0k
  cs_mem_free(bpf);
460
461
  return true;
462
14.1k
}
463
464
#endif