xref: /aosp_15_r20/external/AFLplusplus/src/afl-fuzz-statsd.c (revision 08b48e0b10e97b33e7b60c5b6e2243bd915777f2)
1 /*
2  * This implements rpc.statsd support, see docs/rpc_statsd.md
3  *
4  */
5 
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <sys/socket.h>
9 #include <arpa/inet.h>
10 #include <string.h>
11 #include <sys/types.h>
12 #include <netdb.h>
13 #include <unistd.h>
14 #include "afl-fuzz.h"
15 
16 #define MAX_STATSD_PACKET_SIZE 4096
17 #define MAX_TAG_LEN 200
18 #define METRIC_PREFIX "fuzzing"
19 
20 /* Tags format for metrics
21   DogStatsD:
22   metric.name:<value>|<type>|#key:value,key2:value2
23 
24   InfluxDB
25   metric.name,key=value,key2=value2:<value>|<type>
26 
27   Librato
28   metric.name#key=value,key2=value2:<value>|<type>
29 
30   SignalFX
31   metric.name[key=value,key2=value2]:<value>|<type>
32 
33 */
34 
35 // after the whole metric.
36 #define DOGSTATSD_TAGS_FORMAT "|#banner:%s,afl_version:%s"
37 
38 // just after the metric name.
39 #define LIBRATO_TAGS_FORMAT "#banner=%s,afl_version=%s"
40 #define INFLUXDB_TAGS_FORMAT ",banner=%s,afl_version=%s"
41 #define SIGNALFX_TAGS_FORMAT "[banner=%s,afl_version=%s]"
42 
43 // For DogstatsD
44 #define STATSD_TAGS_TYPE_SUFFIX 1
45 #define STATSD_TAGS_SUFFIX_METRICS                                       \
46   METRIC_PREFIX                                                          \
47   ".cycle_done:%llu|g%s\n" METRIC_PREFIX                                 \
48   ".cycles_wo_finds:%llu|g%s\n" METRIC_PREFIX                            \
49   ".execs_done:%llu|g%s\n" METRIC_PREFIX                                 \
50   ".execs_per_sec:%0.02f|g%s\n" METRIC_PREFIX                            \
51   ".corpus_count:%u|g%s\n" METRIC_PREFIX                                 \
52   ".corpus_favored:%u|g%s\n" METRIC_PREFIX                               \
53   ".corpus_found:%u|g%s\n" METRIC_PREFIX                                 \
54   ".corpus_imported:%u|g%s\n" METRIC_PREFIX                              \
55   ".max_depth:%u|g%s\n" METRIC_PREFIX ".cur_item:%u|g%s\n" METRIC_PREFIX \
56   ".pending_favs:%u|g%s\n" METRIC_PREFIX                                 \
57   ".pending_total:%u|g%s\n" METRIC_PREFIX                                \
58   ".corpus_variable:%u|g%s\n" METRIC_PREFIX                              \
59   ".saved_crashes:%llu|g%s\n" METRIC_PREFIX                              \
60   ".saved_hangs:%llu|g%s\n" METRIC_PREFIX                                \
61   ".total_crashes:%llu|g%s\n" METRIC_PREFIX                              \
62   ".slowest_exec_ms:%u|g%s\n" METRIC_PREFIX                              \
63   ".edges_found:%u|g%s\n" METRIC_PREFIX                                  \
64   ".var_byte_count:%u|g%s\n" METRIC_PREFIX ".havoc_expansion:%u|g%s\n"
65 
66 // For Librato, InfluxDB, SignalFX
67 #define STATSD_TAGS_TYPE_MID 2
68 #define STATSD_TAGS_MID_METRICS                                          \
69   METRIC_PREFIX                                                          \
70   ".cycle_done%s:%llu|g\n" METRIC_PREFIX                                 \
71   ".cycles_wo_finds%s:%llu|g\n" METRIC_PREFIX                            \
72   ".execs_done%s:%llu|g\n" METRIC_PREFIX                                 \
73   ".execs_per_sec%s:%0.02f|g\n" METRIC_PREFIX                            \
74   ".corpus_count%s:%u|g\n" METRIC_PREFIX                                 \
75   ".corpus_favored%s:%u|g\n" METRIC_PREFIX                               \
76   ".corpus_found%s:%u|g\n" METRIC_PREFIX                                 \
77   ".corpus_imported%s:%u|g\n" METRIC_PREFIX                              \
78   ".max_depth%s:%u|g\n" METRIC_PREFIX ".cur_item%s:%u|g\n" METRIC_PREFIX \
79   ".pending_favs%s:%u|g\n" METRIC_PREFIX                                 \
80   ".pending_total%s:%u|g\n" METRIC_PREFIX                                \
81   ".corpus_variable%s:%u|g\n" METRIC_PREFIX                              \
82   ".saved_crashes%s:%llu|g\n" METRIC_PREFIX                              \
83   ".saved_hangs%s:%llu|g\n" METRIC_PREFIX                                \
84   ".total_crashes%s:%llu|g\n" METRIC_PREFIX                              \
85   ".slowest_exec_ms%s:%u|g\n" METRIC_PREFIX                              \
86   ".edges_found%s:%u|g\n" METRIC_PREFIX                                  \
87   ".var_byte_count%s:%u|g\n" METRIC_PREFIX ".havoc_expansion%s:%u|g\n"
88 
statsd_setup_format(afl_state_t * afl)89 void statsd_setup_format(afl_state_t *afl) {
90 
91   if (afl->afl_env.afl_statsd_tags_flavor &&
92       strcmp(afl->afl_env.afl_statsd_tags_flavor, "dogstatsd") == 0) {
93 
94     afl->statsd_tags_format = DOGSTATSD_TAGS_FORMAT;
95     afl->statsd_metric_format = STATSD_TAGS_SUFFIX_METRICS;
96     afl->statsd_metric_format_type = STATSD_TAGS_TYPE_SUFFIX;
97 
98   } else if (afl->afl_env.afl_statsd_tags_flavor &&
99 
100              strcmp(afl->afl_env.afl_statsd_tags_flavor, "librato") == 0) {
101 
102     afl->statsd_tags_format = LIBRATO_TAGS_FORMAT;
103     afl->statsd_metric_format = STATSD_TAGS_MID_METRICS;
104     afl->statsd_metric_format_type = STATSD_TAGS_TYPE_MID;
105 
106   } else if (afl->afl_env.afl_statsd_tags_flavor &&
107 
108              strcmp(afl->afl_env.afl_statsd_tags_flavor, "influxdb") == 0) {
109 
110     afl->statsd_tags_format = INFLUXDB_TAGS_FORMAT;
111     afl->statsd_metric_format = STATSD_TAGS_MID_METRICS;
112     afl->statsd_metric_format_type = STATSD_TAGS_TYPE_MID;
113 
114   } else if (afl->afl_env.afl_statsd_tags_flavor &&
115 
116              strcmp(afl->afl_env.afl_statsd_tags_flavor, "signalfx") == 0) {
117 
118     afl->statsd_tags_format = SIGNALFX_TAGS_FORMAT;
119     afl->statsd_metric_format = STATSD_TAGS_MID_METRICS;
120     afl->statsd_metric_format_type = STATSD_TAGS_TYPE_MID;
121 
122   } else {
123 
124     // No tags at all.
125     afl->statsd_tags_format = "";
126     // Still need to pick a format. Doesn't change anything since if will be
127     // replaced by the empty string anyway.
128     afl->statsd_metric_format = STATSD_TAGS_MID_METRICS;
129     afl->statsd_metric_format_type = STATSD_TAGS_TYPE_MID;
130 
131   }
132 
133 }
134 
statsd_socket_init(afl_state_t * afl)135 int statsd_socket_init(afl_state_t *afl) {
136 
137   /* Default port and host.
138   Will be overwritten by AFL_STATSD_PORT and AFL_STATSD_HOST environment
139   variable, if they exists.
140   */
141   u16   port = STATSD_DEFAULT_PORT;
142   char *host = STATSD_DEFAULT_HOST;
143 
144   if (afl->afl_env.afl_statsd_port) {
145 
146     port = atoi(afl->afl_env.afl_statsd_port);
147 
148   }
149 
150   if (afl->afl_env.afl_statsd_host) { host = afl->afl_env.afl_statsd_host; }
151 
152   int sock;
153   if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
154 
155     FATAL("Failed to create socket");
156 
157   }
158 
159   memset(&afl->statsd_server, 0, sizeof(afl->statsd_server));
160   afl->statsd_server.sin_family = AF_INET;
161   afl->statsd_server.sin_port = htons(port);
162 
163   struct addrinfo *result;
164   struct addrinfo  hints;
165 
166   memset(&hints, 0, sizeof(struct addrinfo));
167   hints.ai_family = AF_INET;
168   hints.ai_socktype = SOCK_DGRAM;
169 
170   if ((getaddrinfo(host, NULL, &hints, &result))) {
171 
172     FATAL("Fail to getaddrinfo");
173 
174   }
175 
176   memcpy(&(afl->statsd_server.sin_addr),
177          &((struct sockaddr_in *)result->ai_addr)->sin_addr,
178          sizeof(struct in_addr));
179   freeaddrinfo(result);
180 
181   return sock;
182 
183 }
184 
statsd_send_metric(afl_state_t * afl)185 int statsd_send_metric(afl_state_t *afl) {
186 
187   char buff[MAX_STATSD_PACKET_SIZE] = {0};
188 
189   /* afl->statsd_sock is set once in the initialisation of afl-fuzz and reused
190   each time If the sendto later fail, we reset it to 0 to be able to recreates
191   it.
192   */
193   if (!afl->statsd_sock) {
194 
195     afl->statsd_sock = statsd_socket_init(afl);
196     if (!afl->statsd_sock) {
197 
198       WARNF("Cannot create socket");
199       return -1;
200 
201     }
202 
203   }
204 
205   statsd_format_metric(afl, buff, MAX_STATSD_PACKET_SIZE);
206   if (sendto(afl->statsd_sock, buff, strlen(buff), 0,
207              (struct sockaddr *)&afl->statsd_server,
208              sizeof(afl->statsd_server)) == -1) {
209 
210     if (!close(afl->statsd_sock)) { PFATAL("Cannot close socket"); }
211     afl->statsd_sock = 0;
212     WARNF("Cannot sendto");
213     return -1;
214 
215   }
216 
217   return 0;
218 
219 }
220 
statsd_format_metric(afl_state_t * afl,char * buff,size_t bufflen)221 int statsd_format_metric(afl_state_t *afl, char *buff, size_t bufflen) {
222 
223   char tags[MAX_TAG_LEN * 2] = {0};
224   if (afl->statsd_tags_format) {
225 
226     snprintf(tags, MAX_TAG_LEN * 2, afl->statsd_tags_format, afl->sync_id,
227              VERSION);
228 
229   }
230 
231   /* Sends multiple metrics with one UDP Packet.
232   bufflen will limit to the max safe size.
233   */
234   if (afl->statsd_metric_format_type == STATSD_TAGS_TYPE_SUFFIX) {
235 
236     snprintf(
237         buff, bufflen, afl->statsd_metric_format,
238         afl->queue_cycle ? (afl->queue_cycle - 1) : 0, tags,
239         afl->cycles_wo_finds, tags, afl->fsrv.total_execs, tags,
240         afl->fsrv.total_execs /
241             ((double)(get_cur_time() + afl->prev_run_time - afl->start_time) /
242              1000),
243         tags, afl->queued_items, tags, afl->queued_favored, tags,
244         afl->queued_discovered, tags, afl->queued_imported, tags,
245         afl->max_depth, tags, afl->current_entry, tags, afl->pending_favored,
246         tags, afl->pending_not_fuzzed, tags, afl->queued_variable, tags,
247         afl->saved_crashes, tags, afl->saved_hangs, tags, afl->total_crashes,
248         tags, afl->slowest_exec_ms, tags,
249         count_non_255_bytes(afl, afl->virgin_bits), tags, afl->var_byte_count,
250         tags, afl->expand_havoc, tags);
251 
252   } else if (afl->statsd_metric_format_type == STATSD_TAGS_TYPE_MID) {
253 
254     snprintf(
255         buff, bufflen, afl->statsd_metric_format, tags,
256         afl->queue_cycle ? (afl->queue_cycle - 1) : 0, tags,
257         afl->cycles_wo_finds, tags, afl->fsrv.total_execs, tags,
258         afl->fsrv.total_execs /
259             ((double)(get_cur_time() + afl->prev_run_time - afl->start_time) /
260              1000),
261         tags, afl->queued_items, tags, afl->queued_favored, tags,
262         afl->queued_discovered, tags, afl->queued_imported, tags,
263         afl->max_depth, tags, afl->current_entry, tags, afl->pending_favored,
264         tags, afl->pending_not_fuzzed, tags, afl->queued_variable, tags,
265         afl->saved_crashes, tags, afl->saved_hangs, tags, afl->total_crashes,
266         tags, afl->slowest_exec_ms, tags,
267         count_non_255_bytes(afl, afl->virgin_bits), tags, afl->var_byte_count,
268         tags, afl->expand_havoc);
269 
270   }
271 
272   return 0;
273 
274 }
275 
276