Coverage Report

Created: 2024-09-08 06:22

/src/capstonenext/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
96.2k
{
16
96.2k
  if (MODE_IS_BIG_ENDIAN(ud->mode))
17
48.1k
    return (((uint16_t)code[0] << 8) | code[1]);
18
48.0k
  else
19
48.0k
    return (((uint16_t)code[1] << 8) | code[0]);
20
96.2k
}
21
22
static uint32_t read_u32(cs_struct *ud, const uint8_t *code)
23
32.4k
{
24
32.4k
  if (MODE_IS_BIG_ENDIAN(ud->mode))
25
16.2k
    return ((uint32_t)read_u16(ud, code) << 16) | read_u16(ud, code + 2);
26
16.2k
  else
27
16.2k
    return ((uint32_t)read_u16(ud, code + 2) << 16) | read_u16(ud, code);
28
32.4k
}
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
32.3k
{
33
32.3k
  bpf_internal *bpf;
34
35
32.3k
  if (code_len < 8)
36
479
    return NULL;
37
31.8k
  bpf = cs_mem_malloc(sizeof(bpf_internal));
38
31.8k
  if (bpf == NULL)
39
0
    return NULL;
40
  /* default value */
41
31.8k
  bpf->insn_size = 8;
42
31.8k
  return bpf;
43
31.8k
}
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
13.5k
{
49
13.5k
  bpf_internal *bpf;
50
51
13.5k
  bpf = alloc_bpf_internal(code_len);
52
13.5k
  if (bpf == NULL)
53
184
    return NULL;
54
55
13.3k
  bpf->op = read_u16(ud, code);
56
13.3k
  bpf->jt = code[2];
57
13.3k
  bpf->jf = code[3];
58
13.3k
  bpf->k = read_u32(ud, code + 4);
59
13.3k
  return bpf;
60
13.5k
}
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.8k
{
66
18.8k
  bpf_internal *bpf;
67
68
18.8k
  bpf = alloc_bpf_internal(code_len);
69
18.8k
  if (bpf == NULL)
70
295
    return NULL;
71
72
18.5k
  bpf->op = (uint16_t)code[0];
73
18.5k
  bpf->dst = code[1] & 0xf;
74
18.5k
  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
18.5k
  if (bpf->op == (BPF_CLASS_LD | BPF_SIZE_DW | BPF_MODE_IMM)) {
79
583
    if (code_len < 16) {
80
2
      cs_mem_free(bpf);
81
2
      return NULL;
82
2
    }
83
581
    bpf->k = read_u32(ud, code + 4) | (((uint64_t)read_u32(ud, code + 12)) << 32);
84
581
    bpf->insn_size = 16;
85
581
  }
86
17.9k
  else {
87
17.9k
    bpf->offset = read_u16(ud, code + 2);
88
17.9k
    bpf->k = read_u32(ud, code + 4);
89
17.9k
  }
90
18.5k
  return bpf;
91
18.5k
}
92
93
11.0k
#define CHECK_READABLE_REG(ud, reg) do { \
94
11.0k
    if (! ((reg) >= BPF_REG_R0 && (reg) <= BPF_REG_R10)) \
95
11.0k
      return false; \
96
11.0k
  } while (0)
97
98
4.51k
#define CHECK_WRITABLE_REG(ud, reg) do { \
99
4.51k
    if (! ((reg) >= BPF_REG_R0 && (reg) < BPF_REG_R10)) \
100
4.51k
      return false; \
101
4.51k
  } while (0)
102
103
11.0k
#define CHECK_READABLE_AND_PUSH(ud, MI, r) do { \
104
11.0k
    CHECK_READABLE_REG(ud, r + BPF_REG_R0); \
105
11.0k
    MCOperand_CreateReg0(MI, r + BPF_REG_R0); \
106
10.9k
  } while (0)
107
108
4.51k
#define CHECK_WRITABLE_AND_PUSH(ud, MI, r) do { \
109
4.51k
    CHECK_WRITABLE_REG(ud, r + BPF_REG_R0); \
110
4.51k
    MCOperand_CreateReg0(MI, r + BPF_REG_R0); \
111
4.50k
  } while (0)
112
113
static bool decodeLoad(cs_struct *ud, MCInst *MI, bpf_internal *bpf)
114
10.1k
{
115
10.1k
  if (!EBPF_MODE(ud)) {
116
    /*
117
     *  +-----+-----------+--------------------+
118
     *  | ldb |    [k]    |       [x+k]        |
119
     *  | ldh |    [k]    |       [x+k]        |
120
     *  +-----+-----------+--------------------+
121
     */
122
5.43k
    if (BPF_SIZE(bpf->op) == BPF_SIZE_DW)
123
10
      return false;
124
5.42k
    if (BPF_SIZE(bpf->op) == BPF_SIZE_B || BPF_SIZE(bpf->op) == BPF_SIZE_H) {
125
      /* no ldx */
126
1.74k
      if (BPF_CLASS(bpf->op) != BPF_CLASS_LD)
127
6
        return false;
128
      /* can only be BPF_ABS and BPF_IND */
129
1.74k
      if (BPF_MODE(bpf->op) == BPF_MODE_ABS) {
130
705
        MCOperand_CreateImm0(MI, bpf->k);
131
705
        return true;
132
705
      }
133
1.03k
      else if (BPF_MODE(bpf->op) == BPF_MODE_IND) {
134
1.02k
        MCOperand_CreateReg0(MI, BPF_REG_X);
135
1.02k
        MCOperand_CreateImm0(MI, bpf->k);
136
1.02k
        return true;
137
1.02k
      }
138
10
      return false;
139
1.74k
    }
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.67k
    switch (BPF_MODE(bpf->op)) {
148
1.22k
    default:
149
1.22k
      break;
150
1.65k
    case BPF_MODE_IMM:
151
1.65k
      MCOperand_CreateImm0(MI, bpf->k);
152
1.65k
      return true;
153
401
    case BPF_MODE_LEN:
154
401
      return true;
155
401
    case BPF_MODE_MEM:
156
401
      MCOperand_CreateImm0(MI, bpf->k);
157
401
      return true;
158
3.67k
    }
159
1.22k
    if (BPF_CLASS(bpf->op) == BPF_CLASS_LD) {
160
885
      if (BPF_MODE(bpf->op) == BPF_MODE_ABS) {
161
460
        MCOperand_CreateImm0(MI, bpf->k);
162
460
        return true;
163
460
      }
164
425
      else if (BPF_MODE(bpf->op) == BPF_MODE_IND) {
165
422
        MCOperand_CreateReg0(MI, BPF_REG_X);
166
422
        MCOperand_CreateImm0(MI, bpf->k);
167
422
        return true;
168
422
      }
169
885
    }
170
336
    else { /* LDX */
171
336
      if (BPF_MODE(bpf->op) == BPF_MODE_MSH) {
172
329
        MCOperand_CreateImm0(MI, bpf->k);
173
329
        return true;
174
329
      }
175
336
    }
176
10
    return false;
177
1.22k
  }
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
4.73k
  if (BPF_CLASS(bpf->op) == BPF_CLASS_LD) {
187
3.33k
    switch (BPF_MODE(bpf->op)) {
188
623
    case BPF_MODE_IMM:
189
623
      if (bpf->op != (BPF_CLASS_LD | BPF_SIZE_DW | BPF_MODE_IMM))
190
42
        return false;
191
581
      CHECK_WRITABLE_AND_PUSH(ud, MI, bpf->dst);
192
577
      MCOperand_CreateImm0(MI, bpf->k);
193
577
      return true;
194
1.51k
    case BPF_MODE_ABS:
195
1.51k
      MCOperand_CreateImm0(MI, bpf->k);
196
1.51k
      return true;
197
1.18k
    case BPF_MODE_IND:
198
1.18k
      CHECK_READABLE_AND_PUSH(ud, MI, bpf->src);
199
1.17k
      MCOperand_CreateImm0(MI, bpf->k);
200
1.17k
      return true;
201
3.33k
    }
202
13
    return false;
203
204
3.33k
  }
205
  /* LDX */
206
1.40k
  if (BPF_MODE(bpf->op) == BPF_MODE_MEM) {
207
1.39k
    CHECK_WRITABLE_AND_PUSH(ud, MI, bpf->dst);
208
1.39k
    CHECK_READABLE_AND_PUSH(ud, MI, bpf->src);
209
1.38k
    MCOperand_CreateImm0(MI, bpf->offset);
210
1.38k
    return true;
211
1.39k
  }
212
13
  return false;
213
1.40k
}
214
215
static bool decodeStore(cs_struct *ud, MCInst *MI, bpf_internal *bpf)
216
3.32k
{
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
3.32k
  if (!EBPF_MODE(ud)) {
224
    /* can only store to M[] */
225
168
    if (bpf->op != (BPF_CLASS(bpf->op) | BPF_MODE_MEM | BPF_SIZE_W))
226
38
      return false;
227
130
    MCOperand_CreateImm0(MI, bpf->k);
228
130
    return true;
229
168
  }
230
231
  /* eBPF */
232
233
3.15k
  if (BPF_MODE(bpf->op) == BPF_MODE_XADD) {
234
109
    if (BPF_CLASS(bpf->op) != BPF_CLASS_STX)
235
5
      return false;
236
104
    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
100
    CHECK_READABLE_AND_PUSH(ud, MI, bpf->dst);
240
97
    MCOperand_CreateImm0(MI, bpf->offset);
241
97
    CHECK_READABLE_AND_PUSH(ud, MI, bpf->src);
242
91
    return true;
243
97
  }
244
245
3.04k
  if (BPF_MODE(bpf->op) != BPF_MODE_MEM)
246
25
    return false;
247
248
  /* st [dst + off], src */
249
3.02k
  CHECK_READABLE_AND_PUSH(ud, MI, bpf->dst);
250
3.01k
  MCOperand_CreateImm0(MI, bpf->offset);
251
3.01k
  if (BPF_CLASS(bpf->op) == BPF_CLASS_ST)
252
1.38k
    MCOperand_CreateImm0(MI, bpf->k);
253
1.62k
  else
254
1.62k
    CHECK_READABLE_AND_PUSH(ud, MI, bpf->src);
255
3.01k
  return true;
256
3.01k
}
257
258
static bool decodeALU(cs_struct *ud, MCInst *MI, bpf_internal *bpf)
259
4.48k
{
260
  /* Set MI->Operands */
261
262
  /* cBPF */
263
4.48k
  if (!EBPF_MODE(ud)) {
264
1.90k
    if (BPF_OP(bpf->op) > BPF_ALU_XOR)
265
2
      return false;
266
    /* cBPF's NEG has no operands */
267
1.90k
    if (BPF_OP(bpf->op) == BPF_ALU_NEG)
268
267
      return true;
269
1.63k
    if (BPF_SRC(bpf->op) == BPF_SRC_K)
270
1.03k
      MCOperand_CreateImm0(MI, bpf->k);
271
601
    else /* BPF_SRC_X */
272
601
      MCOperand_CreateReg0(MI, BPF_REG_X);
273
1.63k
    return true;
274
1.90k
  }
275
276
  /* eBPF */
277
278
2.57k
  if (BPF_OP(bpf->op) > BPF_ALU_END)
279
2
    return false;
280
  /* ENDian's imm must be one of 16, 32, 64 */
281
2.57k
  if (BPF_OP(bpf->op) == BPF_ALU_END) {
282
89
    if (bpf->k != 16 && bpf->k != 32 && bpf->k != 64)
283
39
      return false;
284
50
    if (BPF_CLASS(bpf->op) == BPF_CLASS_ALU64 && BPF_SRC(bpf->op) != BPF_SRC_LITTLE)
285
1
      return false;
286
50
  }
287
288
  /* - op dst, imm
289
   * - op dst, src
290
   * - neg dst
291
   * - le<imm> dst
292
   */
293
  /* every ALU instructions have dst op */
294
2.53k
  CHECK_WRITABLE_AND_PUSH(ud, MI, bpf->dst);
295
296
  /* special cases */
297
2.53k
  if (BPF_OP(bpf->op) == BPF_ALU_NEG)
298
300
    return true;
299
2.23k
  if (BPF_OP(bpf->op) == BPF_ALU_END) {
300
    /* bpf->k must be one of 16, 32, 64 */
301
47
    MCInst_setOpcode(MI, MCInst_getOpcode(MI) | ((uint32_t)bpf->k << 4));
302
47
    return true;
303
47
  }
304
305
  /* normal cases */
306
2.18k
  if (BPF_SRC(bpf->op) == BPF_SRC_K) {
307
1.80k
    MCOperand_CreateImm0(MI, bpf->k);
308
1.80k
  }
309
384
  else { /* BPF_SRC_X */
310
384
    CHECK_READABLE_AND_PUSH(ud, MI, bpf->src);
311
384
  }
312
2.18k
  return true;
313
2.18k
}
314
315
static bool decodeJump(cs_struct *ud, MCInst *MI, bpf_internal *bpf)
316
7.17k
{
317
  /* cBPF and eBPF are very different in class jump */
318
7.17k
  if (!EBPF_MODE(ud)) {
319
1.94k
    if (BPF_OP(bpf->op) > BPF_JUMP_JSET)
320
7
      return false;
321
322
    /* ja is a special case of jumps */
323
1.93k
    if (BPF_OP(bpf->op) == BPF_JUMP_JA) {
324
666
      MCOperand_CreateImm0(MI, bpf->k);
325
666
      return true;
326
666
    }
327
328
1.27k
    if (BPF_SRC(bpf->op) == BPF_SRC_K)
329
653
      MCOperand_CreateImm0(MI, bpf->k);
330
619
    else /* BPF_SRC_X */
331
619
      MCOperand_CreateReg0(MI, BPF_REG_X);
332
1.27k
    MCOperand_CreateImm0(MI, bpf->jt);
333
1.27k
    MCOperand_CreateImm0(MI, bpf->jf);
334
1.27k
  }
335
5.23k
  else {
336
5.23k
    if (BPF_OP(bpf->op) > BPF_JUMP_JSLE)
337
4
      return false;
338
339
    /* No operands for exit */
340
5.22k
    if (BPF_OP(bpf->op) == BPF_JUMP_EXIT)
341
590
      return bpf->op == (BPF_CLASS_JMP | BPF_JUMP_EXIT);
342
4.63k
    if (BPF_OP(bpf->op) == BPF_JUMP_CALL) {
343
1.12k
      if (bpf->op == (BPF_CLASS_JMP | BPF_JUMP_CALL)) {
344
1.02k
        MCOperand_CreateImm0(MI, bpf->k);
345
1.02k
        return true;
346
1.02k
      }
347
94
      if (bpf->op == (BPF_CLASS_JMP | BPF_JUMP_CALL | BPF_SRC_X)) {
348
94
        CHECK_READABLE_AND_PUSH(ud, MI, bpf->k);
349
21
        return true;
350
94
      }
351
0
      return false;
352
94
    }
353
354
    /* ja is a special case of jumps */
355
3.51k
    if (BPF_OP(bpf->op) == BPF_JUMP_JA) {
356
579
      if (BPF_SRC(bpf->op) != BPF_SRC_K)
357
2
        return false;
358
577
      MCOperand_CreateImm0(MI, bpf->offset);
359
577
      return true;
360
579
    }
361
362
    /* <j>  dst, src, +off */
363
2.93k
    CHECK_READABLE_AND_PUSH(ud, MI, bpf->dst);
364
2.92k
    if (BPF_SRC(bpf->op) == BPF_SRC_K)
365
2.70k
      MCOperand_CreateImm0(MI, bpf->k);
366
225
    else
367
225
      CHECK_READABLE_AND_PUSH(ud, MI, bpf->src);
368
2.92k
    MCOperand_CreateImm0(MI, bpf->offset);
369
2.92k
  }
370
4.19k
  return true;
371
7.17k
}
372
373
static bool decodeReturn(cs_struct *ud, MCInst *MI, bpf_internal *bpf)
374
1.94k
{
375
  /* Here only handles the BPF_RET class in cBPF */
376
1.94k
  switch (BPF_RVAL(bpf->op)) {
377
670
  case BPF_SRC_K:
378
670
    MCOperand_CreateImm0(MI, bpf->k);
379
670
    return true;
380
458
  case BPF_SRC_X:
381
458
    MCOperand_CreateReg0(MI, BPF_REG_X);
382
458
    return true;
383
811
  case BPF_SRC_A:
384
811
    MCOperand_CreateReg0(MI, BPF_REG_A);
385
811
    return true;
386
1.94k
  }
387
6
  return false;
388
1.94k
}
389
390
static bool decodeMISC(cs_struct *ud, MCInst *MI, bpf_internal *bpf)
391
81
{
392
81
  uint16_t op = bpf->op ^ BPF_CLASS_MISC;
393
81
  return op == BPF_MISCOP_TAX || op == BPF_MISCOP_TXA;
394
81
}
395
396
///< 1. Check if the instruction is valid
397
///< 2. Set MI->opcode
398
///< 3. Set MI->Operands
399
static bool getInstruction(cs_struct *ud, MCInst *MI, bpf_internal *bpf)
400
31.8k
{
401
31.8k
  cs_detail *detail;
402
403
31.8k
  detail = MI->flat_insn->detail;
404
  // initialize detail
405
31.8k
  if (detail) {
406
31.8k
    memset(detail, 0, offsetof(cs_detail, bpf) + sizeof(cs_bpf));
407
31.8k
  }
408
409
31.8k
  MCInst_clear(MI);
410
31.8k
  MCInst_setOpcode(MI, bpf->op);
411
412
31.8k
  switch (BPF_CLASS(bpf->op)) {
413
0
  default: /* should never happen */
414
0
    return false;
415
7.79k
  case BPF_CLASS_LD:
416
10.1k
  case BPF_CLASS_LDX:
417
10.1k
    return decodeLoad(ud, MI, bpf);
418
1.52k
  case BPF_CLASS_ST:
419
3.32k
  case BPF_CLASS_STX:
420
3.32k
    return decodeStore(ud, MI, bpf);
421
5.98k
  case BPF_CLASS_ALU:
422
5.98k
    return decodeALU(ud, MI, bpf);
423
7.17k
  case BPF_CLASS_JMP:
424
7.17k
    return decodeJump(ud, MI, bpf);
425
1.96k
  case BPF_CLASS_RET:
426
    /* eBPF doesn't have this class */
427
1.96k
    if (EBPF_MODE(ud))
428
19
      return false;
429
1.94k
    return decodeReturn(ud, MI, bpf);
430
3.25k
  case BPF_CLASS_MISC:
431
  /* case BPF_CLASS_ALU64: */
432
3.25k
    if (EBPF_MODE(ud))
433
3.17k
      return decodeALU(ud, MI, bpf);
434
81
    else
435
81
      return decodeMISC(ud, MI, bpf);
436
31.8k
  }
437
31.8k
}
438
439
bool BPF_getInstruction(csh ud, const uint8_t *code, size_t code_len,
440
    MCInst *instr, uint16_t *size, uint64_t address, void *info)
441
32.3k
{
442
32.3k
  cs_struct *cs;
443
32.3k
  bpf_internal *bpf;
444
445
32.3k
  cs = (cs_struct*)ud;
446
32.3k
  if (EBPF_MODE(cs))
447
18.8k
    bpf = fetch_ebpf(cs, code, code_len);
448
13.5k
  else
449
13.5k
    bpf = fetch_cbpf(cs, code, code_len);
450
32.3k
  if (bpf == NULL)
451
481
    return false;
452
31.8k
  if (!getInstruction(cs, instr, bpf)) {
453
466
    cs_mem_free(bpf);
454
466
    return false;
455
466
  }
456
457
31.4k
  *size = bpf->insn_size;
458
31.4k
  cs_mem_free(bpf);
459
460
31.4k
  return true;
461
31.8k
}
462
463
#endif