/src/bufferevent_fuzzer.cc
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright 2023 Google LLC |
2 | | Licensed under the Apache License, Version 2.0 (the "License"); |
3 | | you may not use this file except in compliance with the License. |
4 | | You may obtain a copy of the License at |
5 | | http://www.apache.org/licenses/LICENSE-2.0 |
6 | | Unless required by applicable law or agreed to in writing, software |
7 | | distributed under the License is distributed on an "AS IS" BASIS, |
8 | | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
9 | | See the License for the specific language governing permissions and |
10 | | limitations under the License. |
11 | | */ |
12 | | |
13 | | #include <assert.h> |
14 | | #include <stddef.h> |
15 | | #include <stdint.h> |
16 | | #include <stdlib.h> |
17 | | #include <string> |
18 | | #include <sys/socket.h> |
19 | | |
20 | | #include <fuzzer/FuzzedDataProvider.h> |
21 | | |
22 | | extern "C" { |
23 | | #include "libevent/include/event2/buffer.h" |
24 | | #include "libevent/include/event2/bufferevent.h" |
25 | | #include "libevent/include/event2/event.h" |
26 | | } |
27 | | |
28 | 311 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { |
29 | | |
30 | 311 | FuzzedDataProvider data_provider(data, size); |
31 | | |
32 | 311 | std::string s1 = data_provider.ConsumeRandomLengthString(); |
33 | 311 | std::string s2 = data_provider.ConsumeRandomLengthString(); |
34 | 311 | size_t int1 = data_provider.ConsumeIntegral<size_t>(); |
35 | 311 | size_t int2 = data_provider.ConsumeIntegral<size_t>(); |
36 | 311 | size_t int3 = data_provider.ConsumeIntegral<size_t>(); |
37 | 311 | size_t int4 = data_provider.ConsumeIntegral<size_t>(); |
38 | | |
39 | 311 | int use_pair = int1 % 2; |
40 | 311 | int read_write = int2 % 2; |
41 | 311 | int use_filter = int4 % 2; |
42 | | |
43 | 311 | int options1 = int2 % 16; |
44 | 311 | int options2 = int3 % 16; |
45 | | |
46 | 311 | struct bufferevent *bev1 = NULL, *bev2 = NULL, *bev3 = NULL, *bev4 = NULL, |
47 | 311 | *pair[2]; |
48 | 311 | struct event_base *base = NULL; |
49 | 311 | struct evbuffer *evbuf = NULL; |
50 | 311 | static struct ev_token_bucket_cfg *conn_bucket_cfg = NULL; |
51 | 311 | struct bufferevent_rate_limit_group *bev_rate_group = NULL; |
52 | 311 | char buf[128]; |
53 | | |
54 | | /*create a buffer event*/ |
55 | 311 | base = event_base_new(); |
56 | 311 | if (use_pair == 0) { |
57 | 239 | if (bufferevent_pair_new(base, options1, pair) == -1) { |
58 | 18 | event_base_free(base); |
59 | 18 | return 0; |
60 | 18 | } |
61 | 221 | bev1 = pair[0]; |
62 | 221 | bev2 = pair[1]; |
63 | 221 | assert(bufferevent_pair_get_partner(bev1) != NULL); |
64 | 221 | } else { |
65 | 72 | bev1 = bufferevent_socket_new(base, -1, options1); |
66 | 72 | bev2 = bufferevent_socket_new(base, -1, options2); |
67 | 72 | } |
68 | | |
69 | | /*bufferevent_filter_new*/ |
70 | 293 | if (use_filter == 0) { |
71 | | |
72 | | /*we cannot use BEV_OPT_CLOSE_ON_FREE when freeing bufferevents*/ |
73 | 252 | bev3 = bufferevent_filter_new( |
74 | 252 | bev1, NULL, NULL, options1 & (~BEV_OPT_CLOSE_ON_FREE), NULL, NULL); |
75 | 252 | bev4 = bufferevent_filter_new( |
76 | 252 | bev2, NULL, NULL, options2 & (~BEV_OPT_CLOSE_ON_FREE), NULL, NULL); |
77 | | |
78 | 252 | if (bev1) { |
79 | 235 | bufferevent_free(bev1); |
80 | 235 | } |
81 | 252 | if (bev2) { |
82 | 236 | bufferevent_free(bev2); |
83 | 236 | } |
84 | 252 | } else { |
85 | 41 | bev3 = bev1; |
86 | 41 | bev4 = bev2; |
87 | 41 | } |
88 | | |
89 | 293 | if (!bev3 || !bev4) { |
90 | 45 | goto cleanup; |
91 | 45 | } |
92 | | |
93 | 248 | if (bufferevent_priority_set(bev3, options2) == 0) { |
94 | 5 | assert(bufferevent_get_priority(bev3) == options2); |
95 | 5 | } |
96 | | |
97 | | /*set rate limits*/ |
98 | 248 | assert(bufferevent_set_rate_limit(bev3, NULL) != -1); |
99 | 248 | static struct timeval cfg_tick = {static_cast<__time_t>(int1), |
100 | 248 | static_cast<__suseconds_t>(int2)}; |
101 | 248 | conn_bucket_cfg = ev_token_bucket_cfg_new(int1, int2, int3, int4, &cfg_tick); |
102 | 248 | if (!conn_bucket_cfg) { |
103 | 248 | goto cleanup; |
104 | 248 | } |
105 | | |
106 | 0 | bev_rate_group = bufferevent_rate_limit_group_new(base, conn_bucket_cfg); |
107 | 0 | assert(bufferevent_add_to_rate_limit_group(bev4, bev_rate_group) != -1); |
108 | | |
109 | | /*write and read from buffer events*/ |
110 | 0 | bufferevent_write(bev3, s1.c_str(), s1.size()); |
111 | 0 | bufferevent_write(bev4, s2.c_str(), s2.size()); |
112 | 0 | bufferevent_write_buffer(bev3, bufferevent_get_input(bev4)); |
113 | |
|
114 | 0 | evbuf = evbuffer_new(); |
115 | 0 | bufferevent_read_buffer(bev3, evbuf); |
116 | 0 | evbuffer_free(evbuf); |
117 | 0 | bufferevent_read(bev3, buf, sizeof(buf) - 1); |
118 | 0 | bufferevent_remove_from_rate_limit_group(bev4); |
119 | | |
120 | | /*watermarks*/ |
121 | 0 | if (read_write == 0) { |
122 | 0 | bufferevent_setwatermark(bev4, EV_READ, int1, int2); |
123 | 0 | bufferevent_getwatermark(bev4, EV_READ, &int3, NULL); |
124 | 0 | bufferevent_getwatermark(bev4, EV_READ, NULL, &int4); |
125 | 0 | } else { |
126 | 0 | bufferevent_setwatermark(bev4, EV_WRITE, int1, int2); |
127 | 0 | bufferevent_getwatermark(bev4, EV_WRITE, &int3, NULL); |
128 | 0 | bufferevent_getwatermark(bev4, EV_WRITE, NULL, &int4); |
129 | 0 | } |
130 | |
|
131 | 0 | assert(int1 == int3); |
132 | 0 | assert(int2 == int4); |
133 | | |
134 | | /*clean up*/ |
135 | 293 | cleanup: |
136 | 293 | if (bev3) { |
137 | 260 | bufferevent_free(bev3); |
138 | 260 | } |
139 | 293 | if (bev4) { |
140 | 263 | bufferevent_free(bev4); |
141 | 263 | } |
142 | 293 | if (conn_bucket_cfg) { |
143 | 0 | ev_token_bucket_cfg_free(conn_bucket_cfg); |
144 | 0 | conn_bucket_cfg = NULL; |
145 | 0 | } |
146 | | |
147 | 293 | if (bev_rate_group) { |
148 | 0 | bufferevent_rate_limit_group_free(bev_rate_group); |
149 | 0 | } |
150 | | |
151 | 293 | event_base_free(base); |
152 | | |
153 | 293 | return 0; |
154 | 0 | } |