Coverage Report

Created: 2026-07-30 06:49

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/librabbitmq/fuzz/fuzz_codec.c
Line
Count
Source
1
// Copyright 2007 - 2026, Arthur Chan and the rabbitmq-c contributors.
2
// SPDX-License-Identifier: mit
3
4
#include <stdint.h>
5
#include <stdlib.h>
6
#include <string.h>
7
8
#include <rabbitmq-c/amqp.h>
9
#include <rabbitmq-c/framing.h>
10
11
// Round-trips the AMQP codecs. The existing fuzzers only decode; the generated
12
// serializers (amqp_encode_method/properties/table) and amqp_table_clone are
13
// unreachable from hand-written input. Each mode decodes attacker bytes into the
14
// in-memory struct, then re-encodes/clones it -- the decoder supplies the
15
// adversarial-but-valid structs the encoders would otherwise never see.
16
17
6.89k
#define ENC_BUF_SIZE (1u << 20)
18
19
4.08k
static void roundtrip_method(const uint8_t *p, size_t n) {
20
4.08k
  amqp_pool_t pool;
21
4.08k
  void *decoded = NULL;
22
4.08k
  amqp_method_number_t method_id;
23
4.08k
  amqp_bytes_t encoded;
24
25
4.08k
  if (n < 4) {
26
4
    return;
27
4
  }
28
4.07k
  method_id = ((amqp_method_number_t)p[0] << 24) |
29
4.07k
              ((amqp_method_number_t)p[1] << 16) |
30
4.07k
              ((amqp_method_number_t)p[2] << 8) | (amqp_method_number_t)p[3];
31
4.07k
  encoded.len = n - 4;
32
4.07k
  encoded.bytes = (void *)(p + 4);
33
34
4.07k
  init_amqp_pool(&pool, 4096);
35
4.07k
  if (amqp_decode_method(method_id, &pool, encoded, &decoded) ==
36
4.07k
          AMQP_STATUS_OK &&
37
2.18k
      decoded != NULL) {
38
2.18k
    void *buf = malloc(ENC_BUF_SIZE);
39
2.18k
    if (buf != NULL) {
40
2.18k
      amqp_bytes_t out;
41
2.18k
      out.len = ENC_BUF_SIZE;
42
2.18k
      out.bytes = buf;
43
2.18k
      amqp_encode_method(method_id, decoded, out);
44
2.18k
      free(buf);
45
2.18k
    }
46
2.18k
  }
47
4.07k
  empty_amqp_pool(&pool);
48
4.07k
}
49
50
847
static void roundtrip_properties(const uint8_t *p, size_t n) {
51
847
  amqp_pool_t pool;
52
847
  void *decoded = NULL;
53
847
  uint16_t class_id;
54
847
  amqp_bytes_t encoded;
55
56
847
  if (n < 2) {
57
2
    return;
58
2
  }
59
845
  class_id = ((uint16_t)p[0] << 8) | (uint16_t)p[1];
60
845
  encoded.len = n - 2;
61
845
  encoded.bytes = (void *)(p + 2);
62
63
845
  init_amqp_pool(&pool, 4096);
64
845
  if (amqp_decode_properties(class_id, &pool, encoded, &decoded) ==
65
845
          AMQP_STATUS_OK &&
66
546
      decoded != NULL) {
67
546
    void *buf = malloc(ENC_BUF_SIZE);
68
546
    if (buf != NULL) {
69
546
      amqp_bytes_t out;
70
546
      out.len = ENC_BUF_SIZE;
71
546
      out.bytes = buf;
72
546
      amqp_encode_properties(class_id, decoded, out);
73
546
      free(buf);
74
546
    }
75
546
  }
76
845
  empty_amqp_pool(&pool);
77
845
}
78
79
1.05k
static void roundtrip_table(const uint8_t *p, size_t n) {
80
1.05k
  amqp_pool_t pool;
81
1.05k
  amqp_table_t decoded;
82
1.05k
  amqp_bytes_t encoded;
83
1.05k
  size_t offset = 0;
84
85
1.05k
  encoded.len = n;
86
1.05k
  encoded.bytes = (void *)p;
87
88
1.05k
  init_amqp_pool(&pool, 4096);
89
1.05k
  memset(&decoded, 0, sizeof(decoded));
90
1.05k
  if (amqp_decode_table(encoded, &pool, &decoded, &offset) == AMQP_STATUS_OK) {
91
717
    void *buf = malloc(ENC_BUF_SIZE);
92
717
    if (buf != NULL) {
93
717
      amqp_bytes_t out;
94
717
      size_t out_off = 0;
95
717
      out.len = ENC_BUF_SIZE;
96
717
      out.bytes = buf;
97
717
      amqp_encode_table(out, &decoded, &out_off);
98
717
      free(buf);
99
717
    }
100
717
    {
101
717
      amqp_pool_t clone_pool;
102
717
      amqp_table_t clone;
103
717
      init_amqp_pool(&clone_pool, 4096);
104
717
      memset(&clone, 0, sizeof(clone));
105
717
      amqp_table_clone(&decoded, &clone, &clone_pool);
106
717
      empty_amqp_pool(&clone_pool);
107
717
    }
108
717
  }
109
1.05k
  empty_amqp_pool(&pool);
110
1.05k
}
111
112
// First byte selects the codec; the remainder is the payload, framed like the
113
// matching decode fuzzer (method-id / class-id prefix where applicable).
114
5.98k
extern int LLVMFuzzerTestOneInput(const char *data, size_t size) {
115
5.98k
  const uint8_t *bytes = (const uint8_t *)data;
116
117
5.98k
  if (size < 1) {
118
0
    return 0;
119
0
  }
120
5.98k
  switch (bytes[0] % 3) {
121
4.08k
    case 0:
122
4.08k
      roundtrip_method(bytes + 1, size - 1);
123
4.08k
      break;
124
847
    case 1:
125
847
      roundtrip_properties(bytes + 1, size - 1);
126
847
      break;
127
1.05k
    default:
128
1.05k
      roundtrip_table(bytes + 1, size - 1);
129
1.05k
      break;
130
5.98k
  }
131
5.98k
  return 0;
132
5.98k
}