/src/tinyusb/test/fuzz/dcd_fuzz.cc
Line | Count | Source |
1 | | /* |
2 | | * The MIT License (MIT) |
3 | | * |
4 | | * Copyright (c) 2022 Nathaniel Brough |
5 | | * |
6 | | * Permission is hereby granted, free of charge, to any person obtaining a copy |
7 | | * of this software and associated documentation files (the "Software"), to deal |
8 | | * in the Software without restriction, including without limitation the rights |
9 | | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
10 | | * copies of the Software, and to permit persons to whom the Software is |
11 | | * furnished to do so, subject to the following conditions: |
12 | | * |
13 | | * The above copyright notice and this permission notice shall be included in |
14 | | * all copies or substantial portions of the Software. |
15 | | * |
16 | | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
17 | | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
18 | | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
19 | | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
20 | | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
21 | | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
22 | | * THE SOFTWARE. |
23 | | * |
24 | | */ |
25 | | #include "device/dcd.h" |
26 | | #include "fuzz/fuzz_private.h" |
27 | | #include <assert.h> |
28 | | #include <cstdint> |
29 | | #include <limits> |
30 | | |
31 | 0 | #define UNUSED(x) (void)(x) |
32 | | |
33 | | //--------------------------------------------------------------------+ |
34 | | // State tracker |
35 | | //--------------------------------------------------------------------+ |
36 | | struct State { |
37 | | bool interrupts_enabled; |
38 | | bool sof_enabled; |
39 | | uint8_t address; |
40 | | }; |
41 | | |
42 | | tu_static State state = {false, 0, 0}; |
43 | | |
44 | | //--------------------------------------------------------------------+ |
45 | | // Controller API |
46 | | // All no-ops as we are fuzzing. |
47 | | //--------------------------------------------------------------------+ |
48 | | extern "C" { |
49 | 0 | bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { |
50 | 0 | UNUSED(rhport); |
51 | 0 | UNUSED(rh_init); |
52 | 0 | return true; |
53 | 0 | } |
54 | | |
55 | 0 | void dcd_int_handler(uint8_t rhport) { |
56 | 0 | assert(_fuzz_data_provider.has_value()); |
57 | | |
58 | 0 | if (!state.interrupts_enabled) { |
59 | 0 | return; |
60 | 0 | } |
61 | | |
62 | | // Choose if we want to generate a signal based on the fuzzed data. |
63 | 0 | if (_fuzz_data_provider->ConsumeBool()) { |
64 | 0 | dcd_event_bus_signal( |
65 | 0 | rhport, |
66 | | // Choose a random event based on the fuzz data. |
67 | 0 | (dcd_eventid_t)_fuzz_data_provider->ConsumeIntegralInRange<uint8_t>( |
68 | 0 | DCD_EVENT_INVALID + 1, DCD_EVENT_COUNT - 1), |
69 | | // Identify trigger as either an interrupt or a syncrhonous call |
70 | | // depending on fuzz data. |
71 | 0 | _fuzz_data_provider->ConsumeBool()); |
72 | 0 | } |
73 | |
|
74 | 0 | if (_fuzz_data_provider->ConsumeBool()) { |
75 | 0 | constexpr size_t kSetupFrameLength = 8; |
76 | 0 | std::vector<uint8_t> setup = |
77 | 0 | _fuzz_data_provider->ConsumeBytes<uint8_t>(kSetupFrameLength); |
78 | | // Fuzz consumer may return less than requested. If this is the case |
79 | | // we want to make sure that at least that length is allocated and available |
80 | | // to the signal handler. |
81 | 0 | if (setup.size() != kSetupFrameLength) { |
82 | 0 | setup.resize(kSetupFrameLength); |
83 | 0 | } |
84 | 0 | dcd_event_setup_received(rhport, setup.data(), |
85 | | // Identify trigger as either an interrupt or a |
86 | | // syncrhonous call depending on fuzz data. |
87 | 0 | _fuzz_data_provider->ConsumeBool()); |
88 | 0 | } |
89 | 0 | } |
90 | | |
91 | 0 | void dcd_int_enable(uint8_t rhport) { |
92 | 0 | state.interrupts_enabled = true; |
93 | 0 | UNUSED(rhport); |
94 | 0 | return; |
95 | 0 | } |
96 | | |
97 | 0 | void dcd_int_disable(uint8_t rhport) { |
98 | 0 | state.interrupts_enabled = false; |
99 | 0 | UNUSED(rhport); |
100 | 0 | return; |
101 | 0 | } |
102 | | |
103 | 0 | void dcd_set_address(uint8_t rhport, uint8_t dev_addr) { |
104 | 0 | UNUSED(rhport); |
105 | 0 | state.address = dev_addr; |
106 | | // Respond with status. |
107 | 0 | dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0); |
108 | 0 | return; |
109 | 0 | } |
110 | | |
111 | 0 | void dcd_remote_wakeup(uint8_t rhport) { |
112 | 0 | UNUSED(rhport); |
113 | 0 | return; |
114 | 0 | } |
115 | | |
116 | | void dcd_connect(uint8_t rhport) { |
117 | | UNUSED(rhport); |
118 | | return; |
119 | | } |
120 | | |
121 | | void dcd_disconnect(uint8_t rhport) { |
122 | | UNUSED(rhport); |
123 | | return; |
124 | | } |
125 | | |
126 | 0 | void dcd_sof_enable(uint8_t rhport, bool en) { |
127 | 0 | state.sof_enabled = en; |
128 | 0 | UNUSED(rhport); |
129 | 0 | return; |
130 | 0 | } |
131 | | |
132 | | //--------------------------------------------------------------------+ |
133 | | // Endpoint API |
134 | | //--------------------------------------------------------------------+ |
135 | | |
136 | | // Configure endpoint's registers according to descriptor |
137 | 0 | bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const *desc_ep) { |
138 | 0 | UNUSED(rhport); |
139 | 0 | UNUSED(desc_ep); |
140 | 0 | return _fuzz_data_provider->ConsumeBool(); |
141 | 0 | } |
142 | | |
143 | | // Close all non-control endpoints, cancel all pending transfers if any. |
144 | | // Invoked when switching from a non-zero Configuration by SET_CONFIGURE |
145 | | // therefore required for multiple configuration support. |
146 | 0 | void dcd_edpt_close_all(uint8_t rhport) { |
147 | 0 | UNUSED(rhport); |
148 | 0 | return; |
149 | 0 | } |
150 | | |
151 | | // Close an endpoint. |
152 | | // Since it is weak, caller must TU_ASSERT this function's existence before |
153 | | // calling it. |
154 | 0 | void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) { |
155 | 0 | UNUSED(rhport); |
156 | 0 | UNUSED(ep_addr); |
157 | 0 | return; |
158 | 0 | } |
159 | | |
160 | | // Submit a transfer, When complete dcd_event_xfer_complete() is invoked to |
161 | | // notify the stack |
162 | | bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, |
163 | 0 | uint16_t total_bytes) { |
164 | 0 | UNUSED(rhport); |
165 | 0 | UNUSED(buffer); |
166 | 0 | UNUSED(total_bytes); |
167 | |
|
168 | 0 | uint8_t const dir = tu_edpt_dir(ep_addr); |
169 | |
|
170 | 0 | if (dir == TUSB_DIR_IN) { |
171 | 0 | std::vector<uint8_t> temp = |
172 | 0 | _fuzz_data_provider->ConsumeBytes<uint8_t>(total_bytes); |
173 | 0 | std::copy(temp.begin(), temp.end(), buffer); |
174 | 0 | } |
175 | | // Ignore output data as it's not useful for fuzzing without a more |
176 | | // complex fuzzed backend. But we need to make sure it's not |
177 | | // optimised out. |
178 | 0 | volatile uint8_t *dont_optimise0 = buffer; |
179 | 0 | volatile uint16_t dont_optimise1 = total_bytes; |
180 | 0 | UNUSED(dont_optimise0); |
181 | 0 | UNUSED(dont_optimise1); |
182 | | |
183 | |
|
184 | 0 | return _fuzz_data_provider->ConsumeBool(); |
185 | 0 | } |
186 | | |
187 | | /* TODO: implement a fuzzed version of this. |
188 | | bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t *ff, |
189 | | uint16_t total_bytes) {} |
190 | | */ |
191 | | |
192 | | // Stall endpoint, any queuing transfer should be removed from endpoint |
193 | 0 | void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) { |
194 | |
|
195 | 0 | UNUSED(rhport); |
196 | 0 | UNUSED(ep_addr); |
197 | 0 | return; |
198 | 0 | } |
199 | | |
200 | | // clear stall, data toggle is also reset to DATA0 |
201 | | // This API never calls with control endpoints, since it is auto cleared when |
202 | | // receiving setup packet |
203 | 0 | void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) { |
204 | |
|
205 | 0 | UNUSED(rhport); |
206 | 0 | UNUSED(ep_addr); |
207 | 0 | return; |
208 | 0 | } |
209 | | } |