/src/qpid-proton/c/tests/fuzz/fuzz-connection-driver.c
Line | Count | Source |
1 | | /* |
2 | | * |
3 | | * Licensed to the Apache Software Foundation (ASF) under one |
4 | | * or more contributor license agreements. See the NOTICE file |
5 | | * distributed with this work for additional information |
6 | | * regarding copyright ownership. The ASF licenses this file |
7 | | * to you under the Apache License, Version 2.0 (the |
8 | | * "License"); you may not use this file except in compliance |
9 | | * with the License. You may obtain a copy of the License at |
10 | | * |
11 | | * http://www.apache.org/licenses/LICENSE-2.0 |
12 | | * |
13 | | * Unless required by applicable law or agreed to in writing, |
14 | | * software distributed under the License is distributed on an |
15 | | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
16 | | * KIND, either express or implied. See the License for the |
17 | | * specific language governing permissions and limitations |
18 | | * under the License. |
19 | | * |
20 | | */ |
21 | | |
22 | | #include <stdint.h> |
23 | | #include <stdio.h> |
24 | | #include <stdlib.h> |
25 | | #include <string.h> |
26 | | |
27 | | #include "proton/connection_driver.h" |
28 | | #include "proton/engine.h" |
29 | | #include "proton/logger.h" |
30 | | #include "proton/message.h" |
31 | | #include "proton/object.h" |
32 | | |
33 | | #include "libFuzzingEngine.h" |
34 | | |
35 | | // This fuzzer is a variant of the receive.c proactor example |
36 | | |
37 | 529k | #define MAX_SIZE 1024 |
38 | | |
39 | | typedef char str[MAX_SIZE]; |
40 | | |
41 | | typedef struct app_data_t { |
42 | | str container_id; |
43 | | pn_rwbytes_t message_buffer; |
44 | | int message_count; |
45 | | int received; |
46 | | } app_data_t; |
47 | | |
48 | | static void fdc_write(pn_connection_driver_t *driver); |
49 | | size_t fcd_read(pn_connection_driver_t *driver, uint8_t **data, size_t *size); |
50 | | static void decode_message(pn_delivery_t *dlv); |
51 | | static void handle(app_data_t *app, pn_event_t *event); |
52 | | static void check_condition(pn_event_t *e, pn_condition_t *cond); |
53 | | |
54 | | // const bool VERBOSE = true; |
55 | | const bool VERBOSE = false; |
56 | | // const bool ERRORS = true; |
57 | | const bool ERRORS = false; |
58 | | |
59 | | // I could not get rid of the error messages on stderr in any other way |
60 | 430 | void devnull(intptr_t context, pn_log_subsystem_t sub, pn_log_level_t sev, const char *message) {} |
61 | | |
62 | 26.8k | int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { |
63 | 26.8k | if (VERBOSE) |
64 | 0 | printf("BEGIN LLVMFuzzerTestOneInput\n"); |
65 | 26.8k | app_data_t app = {{0}}; |
66 | 26.8k | sprintf(app.container_id, "%s:%06x", |
67 | 26.8k | "fuzz_connection_driver", rand() & 0xffffff); |
68 | | |
69 | 26.8k | pn_connection_driver_t driver; |
70 | 26.8k | if (pn_connection_driver_init(&driver, NULL, NULL) != 0) { |
71 | 0 | printf("pn_connection_driver_init\n"); |
72 | 0 | exit(1); |
73 | 0 | } |
74 | | |
75 | 26.8k | pn_logger_set_log_sink(pn_default_logger(), devnull, 0); |
76 | | |
77 | 26.8k | uint8_t *data = (uint8_t *)Data; |
78 | 26.8k | size_t size = Size; |
79 | | |
80 | 26.8k | fdc_write(&driver); |
81 | | |
82 | 26.8k | pn_event_t *event; |
83 | 215k | while ((event = pn_connection_driver_next_event(&driver)) != NULL) { |
84 | 188k | handle(&app, event); |
85 | 188k | } |
86 | | |
87 | 26.8k | fdc_write(&driver); |
88 | | |
89 | 34.3k | do { |
90 | 34.3k | fdc_write(&driver); |
91 | 34.3k | fcd_read(&driver, &data, &size); |
92 | 34.3k | if (VERBOSE) |
93 | 0 | printf("size is %d, data is %p\n", (int)size, (void *)data); |
94 | 11.8M | while ((event = pn_connection_driver_next_event(&driver)) != NULL) { |
95 | 11.7M | handle(&app, event); |
96 | 11.7M | } |
97 | 34.3k | } while (size > 0); |
98 | | |
99 | 26.8k | pn_connection_driver_close(&driver); |
100 | 26.8k | pn_connection_driver_destroy(&driver); |
101 | 26.8k | if (VERBOSE) |
102 | 0 | printf("END LLVMFuzzerTestOneInput\n"); |
103 | 26.8k | return 0; |
104 | 26.8k | } |
105 | | |
106 | 11.9M | static void handle(app_data_t *app, pn_event_t *event) { |
107 | 11.9M | switch (pn_event_type(event)) { |
108 | | |
109 | 26.8k | case PN_CONNECTION_INIT: { |
110 | 26.8k | pn_connection_t *c = pn_event_connection(event); |
111 | 26.8k | pn_connection_set_container(c, app->container_id); |
112 | 26.8k | pn_connection_open(c); |
113 | 26.8k | pn_session_t *s = pn_session(c); |
114 | 26.8k | pn_session_open(s); |
115 | 26.8k | pn_link_t *l = pn_receiver(s, "my_receiver"); |
116 | 26.8k | pn_terminus_set_address(pn_link_source(l), NULL); |
117 | 26.8k | pn_link_open(l); |
118 | 26.8k | pn_link_flow(l, 20); |
119 | 26.8k | } break; |
120 | | |
121 | 9.17M | case PN_DELIVERY: { |
122 | | /* A message has been received */ |
123 | 9.17M | pn_link_t *link = NULL; |
124 | 9.17M | pn_delivery_t *dlv = pn_event_delivery(event); |
125 | 9.17M | if (pn_delivery_readable(dlv) && !pn_delivery_partial(dlv)) { |
126 | 265k | link = pn_delivery_link(dlv); |
127 | 265k | decode_message(dlv); |
128 | | /* Accept the delivery */ |
129 | 265k | pn_delivery_update(dlv, PN_ACCEPTED); |
130 | | /* done with the delivery, move to the next and free it */ |
131 | 265k | pn_link_advance(link); |
132 | 265k | pn_delivery_settle(dlv); /* dlv is now freed */ |
133 | 265k | } |
134 | 9.17M | } break; |
135 | | |
136 | 8.52k | case PN_TRANSPORT_ERROR: |
137 | 8.52k | check_condition(event, pn_transport_condition(pn_event_transport(event))); |
138 | 8.52k | pn_connection_close(pn_event_connection(event)); |
139 | 8.52k | break; |
140 | | |
141 | 1.02k | case PN_CONNECTION_REMOTE_CLOSE: |
142 | 1.02k | check_condition(event, |
143 | 1.02k | pn_connection_remote_condition(pn_event_connection(event))); |
144 | 1.02k | pn_connection_close(pn_event_connection(event)); |
145 | 1.02k | break; |
146 | | |
147 | 2.13k | case PN_SESSION_REMOTE_CLOSE: |
148 | 2.13k | check_condition(event, |
149 | 2.13k | pn_session_remote_condition(pn_event_session(event))); |
150 | 2.13k | pn_connection_close(pn_event_connection(event)); |
151 | 2.13k | break; |
152 | | |
153 | 14.3k | case PN_LINK_REMOTE_CLOSE: |
154 | 22.8k | case PN_LINK_REMOTE_DETACH: |
155 | 22.8k | check_condition(event, pn_link_remote_condition(pn_event_link(event))); |
156 | 22.8k | pn_connection_close(pn_event_connection(event)); |
157 | 22.8k | break; |
158 | | |
159 | 2.74M | default: |
160 | 2.74M | break; |
161 | 11.9M | } |
162 | 11.9M | } |
163 | | |
164 | 34.5k | static void check_condition(pn_event_t *e, pn_condition_t *cond) { |
165 | 34.5k | if (VERBOSE) |
166 | 0 | printf("beginning check_condition\n"); |
167 | 34.5k | if (pn_condition_is_set(cond)) { |
168 | 8.56k | if (VERBOSE || ERRORS) |
169 | 0 | fprintf(stderr, "%s: %s: %s\n", pn_event_type_name(pn_event_type(e)), |
170 | 0 | pn_condition_get_name(cond), pn_condition_get_description(cond)); |
171 | 8.56k | } |
172 | 34.5k | } |
173 | | |
174 | 265k | static void decode_message(pn_delivery_t *dlv) { |
175 | 265k | static char buffer[MAX_SIZE]; |
176 | 265k | ssize_t len; |
177 | | // try to decode the message body |
178 | 265k | if (pn_delivery_pending(dlv) < MAX_SIZE) { |
179 | | // read in the raw data |
180 | 263k | len = pn_link_recv(pn_delivery_link(dlv), buffer, MAX_SIZE); |
181 | 263k | if (len > 0) { |
182 | | // decode it into a proton message |
183 | 134k | pn_message_t *m = pn_message(); |
184 | 134k | if (PN_OK == pn_message_decode(m, buffer, len)) { |
185 | 134k | char *s = pn_tostring(pn_message_body(m)); |
186 | 134k | if (ERRORS) |
187 | 0 | printf("%s\n", s); |
188 | 134k | free(s); |
189 | 134k | } |
190 | 134k | pn_message_free(m); |
191 | 134k | } |
192 | 263k | } |
193 | 265k | } |
194 | | |
195 | | // reads up to `size` bytes from `data`, |
196 | | // updates `data` pointer and `size` to the unread portion of original `data`, |
197 | | // returns new value of `size` |
198 | 34.3k | size_t fcd_read(pn_connection_driver_t *driver, uint8_t **data, size_t *size) { |
199 | 34.3k | pn_rwbytes_t buf = pn_connection_driver_read_buffer(driver); |
200 | 34.3k | size_t s = (*size < buf.size) ? *size : buf.size; |
201 | 34.3k | if (buf.start == NULL) { |
202 | | // The engine offered a null buffer for further input. |
203 | | // This is legit, because it is just that the "socket" was closed |
204 | | // for further input, after reading the invalid header. |
205 | 283 | *size = 0; |
206 | 283 | return *size; |
207 | 283 | } |
208 | 34.0k | memcpy(buf.start, *data, s); |
209 | | |
210 | 34.0k | pn_connection_driver_read_done(driver, s); |
211 | 34.0k | *data += s; |
212 | 34.0k | *size -= s; |
213 | | |
214 | 34.0k | return *size; |
215 | 34.3k | } |
216 | | |
217 | | // drops the data in the buffer and reports them as written |
218 | 88.1k | static void fdc_write(pn_connection_driver_t *driver) { |
219 | 88.1k | pn_bytes_t buffer = pn_connection_driver_write_buffer(driver); |
220 | 88.1k | pn_connection_driver_write_done(driver, buffer.size); |
221 | 88.1k | } |