/src/fluent-bit/tests/internal/fuzzers/parser_fuzzer.c
Line | Count | Source |
1 | | /* Fluent Bit |
2 | | * ========== |
3 | | * Copyright (C) 2019-2021 The Fluent Bit Authors |
4 | | * Copyright (C) 2015-2018 Treasure Data Inc. |
5 | | * |
6 | | * Licensed under the Apache License, Version 2.0 (the "License"); |
7 | | * you may not use this file except in compliance with the License. |
8 | | * You may obtain a copy of the License at |
9 | | * |
10 | | * http://www.apache.org/licenses/LICENSE-2.0 |
11 | | * |
12 | | * Unless required by applicable law or agreed to in writing, software |
13 | | * distributed under the License is distributed on an "AS IS" BASIS, |
14 | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
15 | | * See the License for the specific language governing permissions and |
16 | | * limitations under the License. |
17 | | */ |
18 | | #include <stdint.h> |
19 | | #include <string.h> |
20 | | #include <stdlib.h> |
21 | | #include <fluent-bit/flb_utils.h> |
22 | | #include <fluent-bit/flb_time.h> |
23 | | #include <fluent-bit/flb_parser.h> |
24 | | #include <fluent-bit/flb_parser_decoder.h> |
25 | | |
26 | | #include "flb_fuzz_header.h" |
27 | | |
28 | 74.2k | #define TYPES_LEN 5 |
29 | | |
30 | | int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) |
31 | 17.7k | { |
32 | 17.7k | TIMEOUT_GUARD |
33 | | |
34 | 17.7k | char *format = NULL; |
35 | 17.7k | char *time_fmt = NULL; |
36 | 17.7k | char *time_key = NULL; |
37 | 17.7k | char *time_offset = NULL; |
38 | 17.7k | char *pregex = NULL; |
39 | 17.7k | struct flb_parser_types *types = NULL; |
40 | 17.7k | struct flb_config *fuzz_config = NULL; |
41 | 17.7k | struct flb_parser *fuzz_parser = NULL; |
42 | 17.7k | int time_keep = 0; |
43 | 17.7k | int types_len = 0; |
44 | | |
45 | | /* Set fuzzer-malloc chance of failure */ |
46 | 17.7k | flb_malloc_mod = 25000; |
47 | 17.7k | flb_malloc_p = 0; |
48 | | |
49 | 17.7k | if (size < 100) { |
50 | 17 | return 0; |
51 | 17 | } |
52 | | |
53 | | /* json parser */ |
54 | 17.7k | fuzz_config = flb_config_init(); |
55 | | |
56 | | /* format + pregex */ |
57 | 17.7k | if (GET_MOD_EQ(4,0)) { |
58 | 13.3k | format = "json"; |
59 | 13.3k | } |
60 | 4.42k | else if (GET_MOD_EQ(4,1)) { |
61 | 215 | format = "regex"; |
62 | | #ifdef PREG_FUZZ |
63 | | pregex = malloc(30); |
64 | | pregex[29] = '\0'; |
65 | | memcpy(pregex, data, 29); |
66 | | data += 29; |
67 | | size -= 29; |
68 | | #else |
69 | 215 | pregex = "^(?<INT>[^ ]+) (?<FLOAT>[^ ]+) (?<BOOL>[^ ]+) (?<STRING>.+)$"; |
70 | 215 | #endif |
71 | 215 | } |
72 | 4.21k | else if (GET_MOD_EQ(4,2)) { |
73 | 570 | format = "ltsv"; |
74 | 570 | } |
75 | 3.64k | else { |
76 | 3.64k | format = "logfmt"; |
77 | 3.64k | } |
78 | 17.7k | MOVE_INPUT(1); |
79 | | |
80 | | /* time_fmt */ |
81 | 17.7k | if (GET_MOD_EQ(2,1)) { |
82 | 2.89k | time_fmt = get_null_terminated(15, &data, &size); |
83 | 2.89k | } |
84 | 17.7k | MOVE_INPUT(1); |
85 | | |
86 | | /* time_key */ |
87 | 17.7k | if (GET_MOD_EQ(2,1)) { |
88 | 2.50k | time_key = get_null_terminated(15, &data, &size); |
89 | 2.50k | } |
90 | 17.7k | MOVE_INPUT(1); |
91 | | |
92 | | /* time_offset */ |
93 | 17.7k | if (GET_MOD_EQ(2,1)) { |
94 | 594 | time_offset = get_null_terminated(15, &data, &size); |
95 | 594 | } |
96 | 17.7k | MOVE_INPUT(1); |
97 | | |
98 | | /* time_keep */ |
99 | 17.7k | time_keep = (GET_MOD_EQ(2,1)) ? MK_TRUE : MK_FALSE; |
100 | 17.7k | MOVE_INPUT(1); |
101 | | |
102 | | /* types_str */ |
103 | 17.7k | if (GET_MOD_EQ(2,1)) { |
104 | 9.27k | types = flb_malloc(sizeof(struct flb_parser_types) * TYPES_LEN); |
105 | 9.27k | char *parser_type_keys[5] = {"AAA", "BBB", "CCC", "DDD", "EEE" }; |
106 | 9.27k | int parser_types[5] = {FLB_PARSER_TYPE_INT, FLB_PARSER_TYPE_FLOAT, |
107 | 9.27k | FLB_PARSER_TYPE_BOOL, FLB_PARSER_TYPE_STRING, |
108 | 9.27k | FLB_PARSER_TYPE_HEX}; |
109 | 55.6k | for (int i = 0; i < TYPES_LEN; i++) { |
110 | 46.3k | types[i].key = strdup(parser_type_keys[i]); |
111 | 46.3k | types[i].key_len = strlen(parser_type_keys[i]); |
112 | 46.3k | types[i].type = parser_types[i]; |
113 | 46.3k | } |
114 | 9.27k | types_len = TYPES_LEN; |
115 | 9.27k | } |
116 | 17.7k | MOVE_INPUT(1); |
117 | | |
118 | | /* decoders */ |
119 | 17.7k | struct mk_list *list = NULL; |
120 | 17.7k | if (GET_MOD_EQ(2,1)) { |
121 | 9.40k | MOVE_INPUT(1); |
122 | 9.40k | list = flb_malloc(sizeof(struct mk_list)); |
123 | 9.40k | mk_list_init(list); |
124 | | |
125 | 9.40k | struct flb_parser_dec *dec = malloc(sizeof(struct flb_parser_dec)); |
126 | 9.40k | dec->key = flb_sds_create_len("AAA", 3); |
127 | 9.40k | dec->buffer = flb_sds_create_size(FLB_PARSER_DEC_BUF_SIZE); |
128 | 9.40k | dec->add_extra_keys = FLB_TRUE; |
129 | 9.40k | mk_list_init(&dec->rules); |
130 | 9.40k | mk_list_add(&dec->_head, list); |
131 | | |
132 | 9.40k | struct flb_parser_dec_rule *dec_rule = malloc(sizeof(struct flb_parser_dec_rule)); |
133 | 9.40k | dec_rule->type = (int)(data[0] % 0x02); |
134 | 9.40k | MOVE_INPUT(1); |
135 | 9.40k | dec_rule->backend = (int)(data[0] % 0x04); |
136 | 9.40k | MOVE_INPUT(1); |
137 | 9.40k | dec_rule->action = (int)data[0] % 0x03; |
138 | 9.40k | mk_list_add(&dec_rule->_head, &dec->rules); |
139 | | |
140 | 9.40k | if (GET_MOD_EQ(2,1)) { |
141 | 3.84k | struct flb_parser_dec_rule *dec_rule2 = malloc(sizeof(struct flb_parser_dec_rule)); |
142 | 3.84k | dec_rule2->type = (int)(data[0] % 0x02); |
143 | 3.84k | MOVE_INPUT(1); |
144 | 3.84k | dec_rule2->backend = (int)(data[0] % 0x04); |
145 | 3.84k | MOVE_INPUT(1); |
146 | 3.84k | dec_rule->action = (int)data[0] % 0x03; |
147 | 3.84k | mk_list_add(&dec_rule2->_head, &dec->rules); |
148 | 3.84k | } |
149 | 9.40k | } |
150 | 17.7k | MOVE_INPUT(1); |
151 | | /* print our config struct */ |
152 | 17.7k | flb_utils_print_setup(fuzz_config); |
153 | | |
154 | | /* now call into the parser */ |
155 | 17.7k | fuzz_parser = flb_parser_create("fuzzer", format, pregex, FLB_TRUE, |
156 | 17.7k | time_fmt, time_key, time_offset, time_keep, 0, FLB_FALSE, |
157 | 17.7k | FLB_FALSE, types, types_len, list, fuzz_config); |
158 | | |
159 | | /* Second step is to use the random parser to parse random input */ |
160 | 17.7k | if (fuzz_parser != NULL) { |
161 | 17.7k | void *out_buf = NULL; |
162 | 17.7k | size_t out_size = 0; |
163 | 17.7k | struct flb_time out_time; |
164 | 17.7k | flb_parser_do(fuzz_parser, (char*)data, size, |
165 | 17.7k | &out_buf, &out_size, &out_time); |
166 | 17.7k | if (out_buf != NULL) { |
167 | 4.67k | free(out_buf); |
168 | 4.67k | } |
169 | 17.7k | flb_parser_destroy(fuzz_parser); |
170 | 17.7k | } |
171 | 25 | else { |
172 | | /* Parser creation failed but we still need to clean |
173 | | * up types and decoders */ |
174 | 25 | if (types != NULL) { |
175 | 48 | for (int i=0; i< TYPES_LEN; i++){ |
176 | 40 | flb_free(types[i].key); |
177 | 40 | } |
178 | 8 | flb_free(types); |
179 | 8 | } |
180 | 25 | if (list != NULL) { |
181 | 9 | flb_parser_decoder_list_destroy(list); |
182 | 9 | } |
183 | 25 | } |
184 | | |
185 | | /* Cleanup everything but the parser */ |
186 | 17.7k | flb_config_exit(fuzz_config); |
187 | 17.7k | if (time_fmt != NULL) { |
188 | 2.89k | flb_free(time_fmt); |
189 | 2.89k | } |
190 | 17.7k | if (time_key != NULL) { |
191 | 2.50k | flb_free(time_key); |
192 | 2.50k | } |
193 | 17.7k | if (time_offset != NULL) { |
194 | 594 | flb_free(time_offset); |
195 | 594 | } |
196 | | #ifdef PREG_FUZZ |
197 | | if (pregex != NULL) { |
198 | | flb_free(pregex); |
199 | | } |
200 | | #endif |
201 | | |
202 | 17.7k | return 0; |
203 | 17.7k | } |