/src/flac/oss-fuzz/seek.cc
Line | Count | Source |
1 | | /* fuzzer_seek |
2 | | * Copyright (C) 2022-2025 Xiph.Org Foundation |
3 | | * |
4 | | * Redistribution and use in source and binary forms, with or without |
5 | | * modification, are permitted provided that the following conditions |
6 | | * are met: |
7 | | * |
8 | | * - Redistributions of source code must retain the above copyright |
9 | | * notice, this list of conditions and the following disclaimer. |
10 | | * |
11 | | * - Redistributions in binary form must reproduce the above copyright |
12 | | * notice, this list of conditions and the following disclaimer in the |
13 | | * documentation and/or other materials provided with the distribution. |
14 | | * |
15 | | * - Neither the name of the Xiph.org Foundation nor the names of its |
16 | | * contributors may be used to endorse or promote products derived from |
17 | | * this software without specific prior written permission. |
18 | | * |
19 | | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
20 | | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
21 | | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
22 | | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR |
23 | | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
24 | | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
25 | | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
26 | | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
27 | | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
28 | | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
29 | | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
30 | | */ |
31 | | |
32 | | #include <cstdlib> |
33 | | #include <cstring> /* for memcpy */ |
34 | | #include "FLAC/stream_decoder.h" |
35 | | #include "common.h" |
36 | | |
37 | | #if MSAN == 1 |
38 | | extern "C" void __msan_check_mem_is_initialized(const volatile void *x, size_t size); |
39 | | #endif |
40 | | |
41 | | int write_abort_check_counter = -1; |
42 | | int written_uncompressed_bytes = 0; |
43 | | int errors_received_counter = 0; |
44 | | |
45 | | #if 0 /* set to 1 to debug */ |
46 | | #define FPRINTF_DEBUG_ONLY(...) fprintf(__VA_ARGS__) |
47 | | #else |
48 | | #define FPRINTF_DEBUG_ONLY(...) |
49 | | #endif |
50 | | |
51 | 105k | #define CONFIG_LENGTH 3 |
52 | | |
53 | | static FLAC__StreamDecoderWriteStatus write_callback(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 *const buffer[], void *client_data) |
54 | 34.5k | { |
55 | 34.5k | (void)decoder, (void)buffer, (void)client_data; |
56 | 34.5k | if(write_abort_check_counter > 0) { |
57 | 305 | write_abort_check_counter--; |
58 | 305 | if(write_abort_check_counter == 0) |
59 | 22 | return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; |
60 | 34.2k | } else if(write_abort_check_counter == 0) |
61 | | /* This must not happen: write callback called after abort is returned */ |
62 | 0 | abort(); |
63 | | |
64 | 34.5k | written_uncompressed_bytes += frame->header.blocksize * frame->header.channels * frame->header.bits_per_sample / 8; |
65 | 34.5k | if(written_uncompressed_bytes > (1 << 24)) |
66 | 2 | return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; |
67 | | |
68 | | |
69 | 34.5k | if(errors_received_counter > 10000) |
70 | 1 | return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; |
71 | | |
72 | 34.5k | return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; |
73 | 34.5k | } |
74 | | |
75 | | static void error_callback(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus error, void *client_data) |
76 | 346k | { |
77 | 346k | (void)decoder, (void)error, (void)client_data; |
78 | 346k | errors_received_counter++; |
79 | 346k | } |
80 | | |
81 | | |
82 | | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) |
83 | 10.9k | { |
84 | 10.9k | FLAC__bool decoder_valid = true; |
85 | 10.9k | FLAC__StreamDecoder *decoder; |
86 | 10.9k | uint8_t command_length; |
87 | 10.9k | FLAC__bool init_bools[16], ogg; |
88 | | |
89 | 10.9k | if(size < 1) |
90 | 0 | return 1; |
91 | | |
92 | 10.9k | if(data[0] < 128) /* Use MSB as on/off */ |
93 | 5.61k | alloc_check_threshold = data[0]; |
94 | 5.34k | else |
95 | 5.34k | alloc_check_threshold = INT32_MAX; |
96 | 10.9k | alloc_check_counter = 0; |
97 | | |
98 | 10.9k | write_abort_check_counter = -1; |
99 | 10.9k | written_uncompressed_bytes = 0; |
100 | 10.9k | errors_received_counter = 0; |
101 | | |
102 | | /* allocate the decoder */ |
103 | 10.9k | if((decoder = FLAC__stream_decoder_new()) == NULL) { |
104 | 3 | return 1; |
105 | 3 | } |
106 | | |
107 | | /* Use first CONFIG_LENGTH bytes for configuration, leave at least one byte of input */ |
108 | 10.9k | if(size < 1 + CONFIG_LENGTH){ |
109 | 20 | FLAC__stream_decoder_delete(decoder); |
110 | 20 | return 0; |
111 | 20 | } |
112 | | |
113 | | /* bit 8 to 19 bits for configuration bools, bit 20 to 23 for length of command section */ |
114 | 142k | for(int i = 0; i < 12; i++) |
115 | 131k | init_bools[i] = data[1+i/8] & (1 << (i % 8)); |
116 | | |
117 | 10.9k | command_length = data[CONFIG_LENGTH-1] >> 4; |
118 | | |
119 | | /* Leave at least one byte as input */ |
120 | 10.9k | if(command_length >= size - 1 - CONFIG_LENGTH) |
121 | 354 | command_length = size - 1 - CONFIG_LENGTH; |
122 | | |
123 | | /* Dump decoder input to file */ |
124 | 10.9k | { |
125 | 10.9k | FILE * file_to_decode = fopen("/tmp/tmp.flac","w"); |
126 | 10.9k | fwrite(data+CONFIG_LENGTH+command_length,1,size-CONFIG_LENGTH-command_length,file_to_decode); |
127 | 10.9k | fclose(file_to_decode); |
128 | 10.9k | } |
129 | | |
130 | 10.9k | ogg = init_bools[0]; |
131 | | |
132 | 10.9k | FLAC__stream_decoder_set_md5_checking(decoder,init_bools[1]); |
133 | 10.9k | if(init_bools[2]) |
134 | 6.80k | FLAC__stream_decoder_set_metadata_respond_all(decoder); |
135 | 10.9k | if(init_bools[3]) |
136 | 5.06k | FLAC__stream_decoder_set_metadata_ignore_all(decoder); |
137 | 10.9k | if(init_bools[4]) |
138 | 5.18k | FLAC__stream_decoder_set_decode_chained_stream(decoder, true); |
139 | | |
140 | | /* initialize decoder */ |
141 | 10.9k | if(decoder_valid) { |
142 | 10.9k | FLAC__StreamDecoderInitStatus init_status; |
143 | 10.9k | if(ogg) |
144 | 2.54k | init_status = FLAC__stream_decoder_init_ogg_file(decoder, "/tmp/tmp.flac", write_callback, NULL, error_callback, NULL); |
145 | 8.39k | else |
146 | 8.39k | init_status = FLAC__stream_decoder_init_file(decoder, "/tmp/tmp.flac", write_callback, NULL, error_callback, NULL); |
147 | 10.9k | if(init_status != FLAC__STREAM_DECODER_INIT_STATUS_OK) { |
148 | 2 | decoder_valid = false; |
149 | 2 | } |
150 | 10.9k | } |
151 | | |
152 | | /* Run commands */ |
153 | 61.1k | for(uint8_t i = 0; decoder_valid && (i < command_length); i++){ |
154 | 50.2k | const uint8_t * command = data+CONFIG_LENGTH+i; |
155 | 50.2k | uint8_t shift = 1u << (command[0] >> 3); |
156 | 50.2k | FLAC__uint64 seekpos; |
157 | | |
158 | 50.2k | switch(command[0] & 15){ |
159 | 12.8k | case 0: |
160 | 12.8k | FPRINTF_DEBUG_ONLY(stderr,"end_of_stream\n"); |
161 | 12.8k | decoder_valid = FLAC__stream_decoder_process_until_end_of_stream(decoder); |
162 | 12.8k | break; |
163 | 1.74k | case 1: |
164 | 1.74k | FPRINTF_DEBUG_ONLY(stderr,"end_of_metadata\n"); |
165 | 1.74k | decoder_valid = FLAC__stream_decoder_process_until_end_of_metadata(decoder); |
166 | 1.74k | break; |
167 | 1.65k | case 2: |
168 | 1.65k | FPRINTF_DEBUG_ONLY(stderr,"single\n"); |
169 | 1.65k | decoder_valid = FLAC__stream_decoder_process_single(decoder); |
170 | 1.65k | break; |
171 | 853 | case 3: |
172 | 853 | FPRINTF_DEBUG_ONLY(stderr,"skip_single\n"); |
173 | 853 | decoder_valid = FLAC__stream_decoder_skip_single_frame(decoder); |
174 | 853 | break; |
175 | 727 | case 4: |
176 | 727 | FPRINTF_DEBUG_ONLY(stderr,"reset\n"); |
177 | 727 | decoder_valid = FLAC__stream_decoder_reset(decoder); |
178 | 727 | break; |
179 | 1.19k | case 5: |
180 | 1.19k | FPRINTF_DEBUG_ONLY(stderr,"flush\n"); |
181 | 1.19k | decoder_valid = FLAC__stream_decoder_flush(decoder); |
182 | 1.19k | break; |
183 | 6.29k | case 6: |
184 | 18.5k | case 14: |
185 | 18.5k | shift = 1u << (command[0] >> 3); |
186 | 18.5k | FPRINTF_DEBUG_ONLY(stderr,"seek short %hhu\n",shift); |
187 | 18.5k | decoder_valid = FLAC__stream_decoder_seek_absolute(decoder,shift); |
188 | 18.5k | break; |
189 | 1.33k | case 7: |
190 | 1.33k | if(i+8 >= command_length) /* Not enough data available to do this */ |
191 | 509 | break; |
192 | 828 | seekpos = ((FLAC__uint64)command[1] << 56) + |
193 | 828 | ((FLAC__uint64)command[2] << 48) + |
194 | 828 | ((FLAC__uint64)command[3] << 40) + |
195 | 828 | ((FLAC__uint64)command[4] << 32) + |
196 | 828 | ((FLAC__uint64)command[5] << 24) + |
197 | 828 | ((FLAC__uint64)command[6] << 16) + |
198 | 828 | ((FLAC__uint64)command[7] << 8) + |
199 | 828 | command[8]; |
200 | 828 | i+=8; |
201 | 828 | FPRINTF_DEBUG_ONLY(stderr,"seek long %lu\n",seekpos); |
202 | 828 | decoder_valid = FLAC__stream_decoder_seek_absolute(decoder,seekpos); |
203 | 828 | break; |
204 | 628 | case 8: |
205 | | /* Set abort on write callback */ |
206 | 628 | write_abort_check_counter = (command[0] >> 4) + 1; |
207 | 628 | break; |
208 | 1.99k | case 9: |
209 | 1.99k | FPRINTF_DEBUG_ONLY(stderr,"end_of_link\n"); |
210 | 1.99k | decoder_valid = FLAC__stream_decoder_process_until_end_of_link(decoder); |
211 | 1.99k | break; |
212 | 566 | case 10: |
213 | 566 | FPRINTF_DEBUG_ONLY(stderr,"finish_link\n"); |
214 | 566 | if(FLAC__stream_decoder_get_state(decoder) == FLAC__STREAM_DECODER_END_OF_LINK) |
215 | 7 | FLAC__stream_decoder_finish_link(decoder); |
216 | 566 | break; |
217 | 2.65k | case 11: |
218 | 2.65k | FPRINTF_DEBUG_ONLY(stderr,"skip_single_link\n"); |
219 | 2.65k | decoder_valid = FLAC__stream_decoder_skip_single_link(decoder); |
220 | 2.65k | break; |
221 | 3.09k | case 12: |
222 | 3.09k | FPRINTF_DEBUG_ONLY(stderr,"find_total_samples\n"); |
223 | 3.09k | if(FLAC__stream_decoder_find_total_samples(decoder) == 0) { |
224 | 2.54k | FLAC__StreamDecoderState state = FLAC__stream_decoder_get_state(decoder); |
225 | 2.54k | if(state == FLAC__STREAM_DECODER_OGG_ERROR || |
226 | 2.54k | state == FLAC__STREAM_DECODER_SEEK_ERROR || |
227 | 1.57k | state == FLAC__STREAM_DECODER_ABORTED || |
228 | 1.56k | state == FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR || |
229 | 1.56k | state == FLAC__STREAM_DECODER_UNINITIALIZED) |
230 | 978 | decoder_valid = false; |
231 | 2.54k | } |
232 | 3.09k | break; |
233 | 805 | case 13: |
234 | 805 | int32_t retval; |
235 | 805 | FLAC__uint64 *link_lengths; |
236 | 805 | FPRINTF_DEBUG_ONLY(stderr,"get_link_lengths\n"); |
237 | 805 | retval = FLAC__stream_decoder_get_link_lengths(decoder, &link_lengths); |
238 | 805 | if(retval == FLAC__STREAM_DECODER_GET_LINK_LENGTHS_MEMORY_ALLOCATION_ERROR) { |
239 | 0 | decoder_valid = false; |
240 | 0 | } |
241 | 805 | if(retval > 0) { |
242 | 28.9k | for(int32_t j = 0; j < retval; j++) { |
243 | | #if MSAN == 1 |
244 | | __msan_check_mem_is_initialized(&link_lengths[j],sizeof(link_lengths[j])); |
245 | | #else |
246 | 28.7k | ; |
247 | 28.7k | #endif |
248 | 28.7k | } |
249 | 210 | free(link_lengths); |
250 | 210 | } |
251 | 805 | break; |
252 | | /* case 14 is already used above */ |
253 | 50.2k | } |
254 | 50.2k | if(!decoder_valid) { |
255 | | /* Try again if possible */ |
256 | 33.4k | FLAC__StreamDecoderState state = FLAC__stream_decoder_get_state(decoder); |
257 | 33.4k | if(state != FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR && state != FLAC__STREAM_DECODER_ABORTED) { |
258 | 33.2k | FPRINTF_DEBUG_ONLY(stderr,"reset invalid\n"); |
259 | 33.2k | decoder_valid = FLAC__stream_decoder_reset(decoder); |
260 | 33.2k | } |
261 | 33.4k | } |
262 | 50.2k | } |
263 | | |
264 | 10.9k | FLAC__stream_decoder_finish(decoder); |
265 | | |
266 | 10.9k | FLAC__stream_decoder_delete(decoder); |
267 | | |
268 | 10.9k | return 0; |
269 | 10.9k | } |
270 | | |