/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 | 106k | #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 | 45.1k | { |
55 | 45.1k | (void)decoder, (void)buffer, (void)client_data; |
56 | 45.1k | if(write_abort_check_counter > 0) { |
57 | 327 | write_abort_check_counter--; |
58 | 327 | if(write_abort_check_counter == 0) |
59 | 23 | return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; |
60 | 44.7k | } else if(write_abort_check_counter == 0) |
61 | | /* This must not happen: write callback called after abort is returned */ |
62 | 0 | abort(); |
63 | | |
64 | 45.0k | written_uncompressed_bytes += frame->header.blocksize * frame->header.channels * frame->header.bits_per_sample / 8; |
65 | 45.0k | if(written_uncompressed_bytes > (1 << 24)) |
66 | 2 | return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; |
67 | | |
68 | | |
69 | 45.0k | if(errors_received_counter > 10000) |
70 | 1 | return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; |
71 | | |
72 | 45.0k | return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; |
73 | 45.0k | } |
74 | | |
75 | | static void error_callback(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus error, void *client_data) |
76 | 394k | { |
77 | 394k | (void)decoder, (void)error, (void)client_data; |
78 | 394k | errors_received_counter++; |
79 | 394k | } |
80 | | |
81 | | |
82 | | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) |
83 | 11.0k | { |
84 | 11.0k | FLAC__bool decoder_valid = true; |
85 | 11.0k | FLAC__StreamDecoder *decoder; |
86 | 11.0k | uint8_t command_length; |
87 | 11.0k | FLAC__bool init_bools[16], ogg; |
88 | | |
89 | 11.0k | if(size < 1) |
90 | 0 | return 1; |
91 | | |
92 | 11.0k | if(data[0] < 128) /* Use MSB as on/off */ |
93 | 5.59k | alloc_check_threshold = data[0]; |
94 | 5.43k | else |
95 | 5.43k | alloc_check_threshold = INT32_MAX; |
96 | 11.0k | alloc_check_counter = 0; |
97 | | |
98 | 11.0k | write_abort_check_counter = -1; |
99 | 11.0k | written_uncompressed_bytes = 0; |
100 | 11.0k | errors_received_counter = 0; |
101 | | |
102 | | /* allocate the decoder */ |
103 | 11.0k | 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 | 11.0k | if(size < 1 + CONFIG_LENGTH){ |
109 | 19 | FLAC__stream_decoder_delete(decoder); |
110 | 19 | return 0; |
111 | 19 | } |
112 | | |
113 | | /* bit 8 to 19 bits for configuration bools, bit 20 to 23 for length of command section */ |
114 | 143k | for(int i = 0; i < 12; i++) |
115 | 132k | init_bools[i] = data[1+i/8] & (1 << (i % 8)); |
116 | | |
117 | 11.0k | command_length = data[CONFIG_LENGTH-1] >> 4; |
118 | | |
119 | | /* Leave at least one byte as input */ |
120 | 11.0k | if(command_length >= size - 1 - CONFIG_LENGTH) |
121 | 349 | command_length = size - 1 - CONFIG_LENGTH; |
122 | | |
123 | | /* Dump decoder input to file */ |
124 | 11.0k | { |
125 | 11.0k | FILE * file_to_decode = fopen("/tmp/tmp.flac","w"); |
126 | 11.0k | fwrite(data+CONFIG_LENGTH+command_length,1,size-CONFIG_LENGTH-command_length,file_to_decode); |
127 | 11.0k | fclose(file_to_decode); |
128 | 11.0k | } |
129 | | |
130 | 11.0k | ogg = init_bools[0]; |
131 | | |
132 | 11.0k | FLAC__stream_decoder_set_md5_checking(decoder,init_bools[1]); |
133 | 11.0k | if(init_bools[2]) |
134 | 7.06k | FLAC__stream_decoder_set_metadata_respond_all(decoder); |
135 | 11.0k | if(init_bools[3]) |
136 | 5.09k | FLAC__stream_decoder_set_metadata_ignore_all(decoder); |
137 | 11.0k | if(init_bools[4]) |
138 | 5.14k | FLAC__stream_decoder_set_decode_chained_stream(decoder, true); |
139 | | |
140 | | /* initialize decoder */ |
141 | 11.0k | if(decoder_valid) { |
142 | 11.0k | FLAC__StreamDecoderInitStatus init_status; |
143 | 11.0k | if(ogg) |
144 | 2.52k | init_status = FLAC__stream_decoder_init_ogg_file(decoder, "/tmp/tmp.flac", write_callback, NULL, error_callback, NULL); |
145 | 8.48k | else |
146 | 8.48k | init_status = FLAC__stream_decoder_init_file(decoder, "/tmp/tmp.flac", write_callback, NULL, error_callback, NULL); |
147 | 11.0k | if(init_status != FLAC__STREAM_DECODER_INIT_STATUS_OK) { |
148 | 1 | decoder_valid = false; |
149 | 1 | } |
150 | 11.0k | } |
151 | | |
152 | | /* Run commands */ |
153 | 62.1k | for(uint8_t i = 0; decoder_valid && (i < command_length); i++){ |
154 | 51.1k | const uint8_t * command = data+CONFIG_LENGTH+i; |
155 | 51.1k | uint8_t shift = 1u << (command[0] >> 3); |
156 | 51.1k | FLAC__uint64 seekpos; |
157 | | |
158 | 51.1k | switch(command[0] & 15){ |
159 | 12.7k | case 0: |
160 | 12.7k | FPRINTF_DEBUG_ONLY(stderr,"end_of_stream\n"); |
161 | 12.7k | decoder_valid = FLAC__stream_decoder_process_until_end_of_stream(decoder); |
162 | 12.7k | break; |
163 | 1.85k | case 1: |
164 | 1.85k | FPRINTF_DEBUG_ONLY(stderr,"end_of_metadata\n"); |
165 | 1.85k | decoder_valid = FLAC__stream_decoder_process_until_end_of_metadata(decoder); |
166 | 1.85k | break; |
167 | 1.53k | case 2: |
168 | 1.53k | FPRINTF_DEBUG_ONLY(stderr,"single\n"); |
169 | 1.53k | decoder_valid = FLAC__stream_decoder_process_single(decoder); |
170 | 1.53k | break; |
171 | 850 | case 3: |
172 | 850 | FPRINTF_DEBUG_ONLY(stderr,"skip_single\n"); |
173 | 850 | decoder_valid = FLAC__stream_decoder_skip_single_frame(decoder); |
174 | 850 | break; |
175 | 838 | case 4: |
176 | 838 | FPRINTF_DEBUG_ONLY(stderr,"reset\n"); |
177 | 838 | decoder_valid = FLAC__stream_decoder_reset(decoder); |
178 | 838 | 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.15k | case 6: |
184 | 19.2k | case 14: |
185 | 19.2k | shift = 1u << (command[0] >> 3); |
186 | 19.2k | FPRINTF_DEBUG_ONLY(stderr,"seek short %hhu\n",shift); |
187 | 19.2k | decoder_valid = FLAC__stream_decoder_seek_absolute(decoder,shift); |
188 | 19.2k | break; |
189 | 1.29k | case 7: |
190 | 1.29k | if(i+8 >= command_length) /* Not enough data available to do this */ |
191 | 473 | break; |
192 | 825 | seekpos = ((FLAC__uint64)command[1] << 56) + |
193 | 825 | ((FLAC__uint64)command[2] << 48) + |
194 | 825 | ((FLAC__uint64)command[3] << 40) + |
195 | 825 | ((FLAC__uint64)command[4] << 32) + |
196 | 825 | ((FLAC__uint64)command[5] << 24) + |
197 | 825 | ((FLAC__uint64)command[6] << 16) + |
198 | 825 | ((FLAC__uint64)command[7] << 8) + |
199 | 825 | command[8]; |
200 | 825 | i+=8; |
201 | 825 | FPRINTF_DEBUG_ONLY(stderr,"seek long %lu\n",seekpos); |
202 | 825 | decoder_valid = FLAC__stream_decoder_seek_absolute(decoder,seekpos); |
203 | 825 | break; |
204 | 678 | case 8: |
205 | | /* Set abort on write callback */ |
206 | 678 | write_abort_check_counter = (command[0] >> 4) + 1; |
207 | 678 | break; |
208 | 2.14k | case 9: |
209 | 2.14k | FPRINTF_DEBUG_ONLY(stderr,"end_of_link\n"); |
210 | 2.14k | decoder_valid = FLAC__stream_decoder_process_until_end_of_link(decoder); |
211 | 2.14k | break; |
212 | 633 | case 10: |
213 | 633 | FPRINTF_DEBUG_ONLY(stderr,"finish_link\n"); |
214 | 633 | if(FLAC__stream_decoder_get_state(decoder) == FLAC__STREAM_DECODER_END_OF_LINK) |
215 | 9 | FLAC__stream_decoder_finish_link(decoder); |
216 | 633 | break; |
217 | 2.51k | case 11: |
218 | 2.51k | FPRINTF_DEBUG_ONLY(stderr,"skip_single_link\n"); |
219 | 2.51k | decoder_valid = FLAC__stream_decoder_skip_single_link(decoder); |
220 | 2.51k | break; |
221 | 3.17k | case 12: |
222 | 3.17k | FPRINTF_DEBUG_ONLY(stderr,"find_total_samples\n"); |
223 | 3.17k | if(FLAC__stream_decoder_find_total_samples(decoder) == 0) { |
224 | 2.56k | FLAC__StreamDecoderState state = FLAC__stream_decoder_get_state(decoder); |
225 | 2.56k | if(state == FLAC__STREAM_DECODER_OGG_ERROR || |
226 | 2.56k | state == FLAC__STREAM_DECODER_SEEK_ERROR || |
227 | 1.56k | state == FLAC__STREAM_DECODER_ABORTED || |
228 | 1.55k | state == FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR || |
229 | 1.55k | state == FLAC__STREAM_DECODER_UNINITIALIZED) |
230 | 1.01k | decoder_valid = false; |
231 | 2.56k | } |
232 | 3.17k | break; |
233 | 737 | case 13: |
234 | 737 | int32_t retval; |
235 | 737 | FLAC__uint64 *link_lengths; |
236 | 737 | FPRINTF_DEBUG_ONLY(stderr,"get_link_lengths\n"); |
237 | 737 | retval = FLAC__stream_decoder_get_link_lengths(decoder, &link_lengths); |
238 | 737 | if(retval == FLAC__STREAM_DECODER_GET_LINK_LENGTHS_MEMORY_ALLOCATION_ERROR) { |
239 | 0 | decoder_valid = false; |
240 | 0 | } |
241 | 737 | if(retval > 0) { |
242 | 71.4k | 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 | 71.2k | ; |
247 | 71.2k | #endif |
248 | 71.2k | } |
249 | 216 | free(link_lengths); |
250 | 216 | } |
251 | 737 | break; |
252 | | /* case 14 is already used above */ |
253 | 51.1k | } |
254 | 51.1k | if(!decoder_valid) { |
255 | | /* Try again if possible */ |
256 | 34.0k | FLAC__StreamDecoderState state = FLAC__stream_decoder_get_state(decoder); |
257 | 34.0k | if(state != FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR && state != FLAC__STREAM_DECODER_ABORTED) { |
258 | 33.8k | FPRINTF_DEBUG_ONLY(stderr,"reset invalid\n"); |
259 | 33.8k | decoder_valid = FLAC__stream_decoder_reset(decoder); |
260 | 33.8k | } |
261 | 34.0k | } |
262 | 51.1k | } |
263 | | |
264 | 11.0k | FLAC__stream_decoder_finish(decoder); |
265 | | |
266 | 11.0k | FLAC__stream_decoder_delete(decoder); |
267 | | |
268 | 11.0k | return 0; |
269 | 11.0k | } |
270 | | |