1*600f14f4SXin Li /* fuzzer_seek
2*600f14f4SXin Li * Copyright (C) 2022-2023 Xiph.Org Foundation
3*600f14f4SXin Li *
4*600f14f4SXin Li * Redistribution and use in source and binary forms, with or without
5*600f14f4SXin Li * modification, are permitted provided that the following conditions
6*600f14f4SXin Li * are met:
7*600f14f4SXin Li *
8*600f14f4SXin Li * - Redistributions of source code must retain the above copyright
9*600f14f4SXin Li * notice, this list of conditions and the following disclaimer.
10*600f14f4SXin Li *
11*600f14f4SXin Li * - Redistributions in binary form must reproduce the above copyright
12*600f14f4SXin Li * notice, this list of conditions and the following disclaimer in the
13*600f14f4SXin Li * documentation and/or other materials provided with the distribution.
14*600f14f4SXin Li *
15*600f14f4SXin Li * - Neither the name of the Xiph.org Foundation nor the names of its
16*600f14f4SXin Li * contributors may be used to endorse or promote products derived from
17*600f14f4SXin Li * this software without specific prior written permission.
18*600f14f4SXin Li *
19*600f14f4SXin Li * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20*600f14f4SXin Li * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21*600f14f4SXin Li * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22*600f14f4SXin Li * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
23*600f14f4SXin Li * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24*600f14f4SXin Li * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25*600f14f4SXin Li * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
26*600f14f4SXin Li * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
27*600f14f4SXin Li * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
28*600f14f4SXin Li * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29*600f14f4SXin Li * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30*600f14f4SXin Li */
31*600f14f4SXin Li
32*600f14f4SXin Li #include <cstdlib>
33*600f14f4SXin Li #include <cstring> /* for memcpy */
34*600f14f4SXin Li #include "FLAC/stream_decoder.h"
35*600f14f4SXin Li #include "common.h"
36*600f14f4SXin Li
37*600f14f4SXin Li int write_abort_check_counter = -1;
38*600f14f4SXin Li
39*600f14f4SXin Li #if 0 /* set to 1 to debug */
40*600f14f4SXin Li #define FPRINTF_DEBUG_ONLY(...) fprintf(__VA_ARGS__)
41*600f14f4SXin Li #else
42*600f14f4SXin Li #define FPRINTF_DEBUG_ONLY(...)
43*600f14f4SXin Li #endif
44*600f14f4SXin Li
45*600f14f4SXin Li #define CONFIG_LENGTH 2
46*600f14f4SXin Li
write_callback(const FLAC__StreamDecoder * decoder,const FLAC__Frame * frame,const FLAC__int32 * const buffer[],void * client_data)47*600f14f4SXin Li static FLAC__StreamDecoderWriteStatus write_callback(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 *const buffer[], void *client_data)
48*600f14f4SXin Li {
49*600f14f4SXin Li (void)decoder, (void)frame, (void)buffer, (void)client_data;
50*600f14f4SXin Li if(write_abort_check_counter > 0) {
51*600f14f4SXin Li write_abort_check_counter--;
52*600f14f4SXin Li if(write_abort_check_counter == 0)
53*600f14f4SXin Li return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
54*600f14f4SXin Li } else if(write_abort_check_counter == 0)
55*600f14f4SXin Li /* This must not happen: write callback called after abort is returned */
56*600f14f4SXin Li abort();
57*600f14f4SXin Li return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
58*600f14f4SXin Li }
59*600f14f4SXin Li
error_callback(const FLAC__StreamDecoder * decoder,FLAC__StreamDecoderErrorStatus error,void * client_data)60*600f14f4SXin Li static void error_callback(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus error, void *client_data)
61*600f14f4SXin Li {
62*600f14f4SXin Li (void)decoder, (void)error, (void)client_data;
63*600f14f4SXin Li }
64*600f14f4SXin Li
65*600f14f4SXin Li
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)66*600f14f4SXin Li extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
67*600f14f4SXin Li {
68*600f14f4SXin Li FLAC__bool decoder_valid = true;
69*600f14f4SXin Li FLAC__StreamDecoder *decoder;
70*600f14f4SXin Li uint8_t command_length;
71*600f14f4SXin Li FLAC__bool init_bools[16], ogg;
72*600f14f4SXin Li
73*600f14f4SXin Li if(size > 2 && data[1] < 128) /* Use MSB as on/off */
74*600f14f4SXin Li alloc_check_threshold = data[1];
75*600f14f4SXin Li else
76*600f14f4SXin Li alloc_check_threshold = INT32_MAX;
77*600f14f4SXin Li alloc_check_counter = 0;
78*600f14f4SXin Li
79*600f14f4SXin Li write_abort_check_counter = -1;
80*600f14f4SXin Li
81*600f14f4SXin Li /* allocate the decoder */
82*600f14f4SXin Li if((decoder = FLAC__stream_decoder_new()) == NULL) {
83*600f14f4SXin Li fprintf(stderr, "ERROR: allocating decoder\n");
84*600f14f4SXin Li return 1;
85*600f14f4SXin Li }
86*600f14f4SXin Li
87*600f14f4SXin Li /* Use first byte for configuration, leave at least one byte of input */
88*600f14f4SXin Li if(size < 1 + CONFIG_LENGTH){
89*600f14f4SXin Li FLAC__stream_decoder_delete(decoder);
90*600f14f4SXin Li return 0;
91*600f14f4SXin Li }
92*600f14f4SXin Li
93*600f14f4SXin Li /* First 4 bits for configuration bools, next 4 for length of command section */
94*600f14f4SXin Li for(int i = 0; i < 4; i++)
95*600f14f4SXin Li init_bools[i] = data[i/8] & (1 << (i % 8));
96*600f14f4SXin Li
97*600f14f4SXin Li command_length = data[0] >> 4;
98*600f14f4SXin Li
99*600f14f4SXin Li /* Leave at least one byte as input */
100*600f14f4SXin Li if(command_length >= size - 1 - CONFIG_LENGTH)
101*600f14f4SXin Li command_length = size - 1 - CONFIG_LENGTH;
102*600f14f4SXin Li
103*600f14f4SXin Li /* Dump decoder input to file */
104*600f14f4SXin Li {
105*600f14f4SXin Li FILE * file_to_decode = fopen("/tmp/tmp.flac","w");
106*600f14f4SXin Li fwrite(data+CONFIG_LENGTH+command_length,1,size-CONFIG_LENGTH-command_length,file_to_decode);
107*600f14f4SXin Li fclose(file_to_decode);
108*600f14f4SXin Li }
109*600f14f4SXin Li
110*600f14f4SXin Li ogg = init_bools[0];
111*600f14f4SXin Li
112*600f14f4SXin Li FLAC__stream_decoder_set_md5_checking(decoder,init_bools[1]);
113*600f14f4SXin Li if(init_bools[2])
114*600f14f4SXin Li FLAC__stream_decoder_set_metadata_respond_all(decoder);
115*600f14f4SXin Li if(init_bools[3])
116*600f14f4SXin Li FLAC__stream_decoder_set_metadata_ignore_all(decoder);
117*600f14f4SXin Li
118*600f14f4SXin Li /* initialize decoder */
119*600f14f4SXin Li if(decoder_valid) {
120*600f14f4SXin Li FLAC__StreamDecoderInitStatus init_status;
121*600f14f4SXin Li if(ogg)
122*600f14f4SXin Li init_status = FLAC__stream_decoder_init_ogg_file(decoder, "/tmp/tmp.flac", write_callback, NULL, error_callback, NULL);
123*600f14f4SXin Li else
124*600f14f4SXin Li init_status = FLAC__stream_decoder_init_file(decoder, "/tmp/tmp.flac", write_callback, NULL, error_callback, NULL);
125*600f14f4SXin Li if(init_status != FLAC__STREAM_DECODER_INIT_STATUS_OK) {
126*600f14f4SXin Li decoder_valid = false;
127*600f14f4SXin Li }
128*600f14f4SXin Li }
129*600f14f4SXin Li
130*600f14f4SXin Li /* Run commands */
131*600f14f4SXin Li for(uint8_t i = 0; decoder_valid && (i < command_length); i++){
132*600f14f4SXin Li const uint8_t * command = data+CONFIG_LENGTH+i;
133*600f14f4SXin Li uint8_t shift = 1u << (command[0] >> 3);
134*600f14f4SXin Li FLAC__uint64 seekpos;
135*600f14f4SXin Li
136*600f14f4SXin Li switch(command[0] & 15){
137*600f14f4SXin Li case 0:
138*600f14f4SXin Li FPRINTF_DEBUG_ONLY(stderr,"end_of_stream\n");
139*600f14f4SXin Li decoder_valid = FLAC__stream_decoder_process_until_end_of_stream(decoder);
140*600f14f4SXin Li break;
141*600f14f4SXin Li case 1:
142*600f14f4SXin Li FPRINTF_DEBUG_ONLY(stderr,"end_of_metadata\n");
143*600f14f4SXin Li decoder_valid = FLAC__stream_decoder_process_until_end_of_metadata(decoder);
144*600f14f4SXin Li break;
145*600f14f4SXin Li case 2:
146*600f14f4SXin Li FPRINTF_DEBUG_ONLY(stderr,"single\n");
147*600f14f4SXin Li decoder_valid = FLAC__stream_decoder_process_single(decoder);
148*600f14f4SXin Li break;
149*600f14f4SXin Li case 3:
150*600f14f4SXin Li FPRINTF_DEBUG_ONLY(stderr,"skip_single\n");
151*600f14f4SXin Li decoder_valid = FLAC__stream_decoder_skip_single_frame(decoder);
152*600f14f4SXin Li break;
153*600f14f4SXin Li case 4:
154*600f14f4SXin Li FPRINTF_DEBUG_ONLY(stderr,"reset\n");
155*600f14f4SXin Li decoder_valid = FLAC__stream_decoder_reset(decoder);
156*600f14f4SXin Li break;
157*600f14f4SXin Li case 5:
158*600f14f4SXin Li FPRINTF_DEBUG_ONLY(stderr,"flush\n");
159*600f14f4SXin Li decoder_valid = FLAC__stream_decoder_flush(decoder);
160*600f14f4SXin Li break;
161*600f14f4SXin Li case 6:
162*600f14f4SXin Li case 14:
163*600f14f4SXin Li shift = 1u << (command[0] >> 3);
164*600f14f4SXin Li FPRINTF_DEBUG_ONLY(stderr,"seek short %hhu\n",shift);
165*600f14f4SXin Li decoder_valid = FLAC__stream_decoder_seek_absolute(decoder,shift);
166*600f14f4SXin Li break;
167*600f14f4SXin Li case 7:
168*600f14f4SXin Li if(i+8 >= command_length) /* Not enough data available to do this */
169*600f14f4SXin Li break;
170*600f14f4SXin Li seekpos = ((FLAC__uint64)command[1] << 56) +
171*600f14f4SXin Li ((FLAC__uint64)command[2] << 48) +
172*600f14f4SXin Li ((FLAC__uint64)command[3] << 40) +
173*600f14f4SXin Li ((FLAC__uint64)command[4] << 32) +
174*600f14f4SXin Li ((FLAC__uint64)command[5] << 24) +
175*600f14f4SXin Li ((FLAC__uint64)command[6] << 16) +
176*600f14f4SXin Li ((FLAC__uint64)command[7] << 8) +
177*600f14f4SXin Li command[8];
178*600f14f4SXin Li i+=8;
179*600f14f4SXin Li FPRINTF_DEBUG_ONLY(stderr,"seek long %lu\n",seekpos);
180*600f14f4SXin Li decoder_valid = FLAC__stream_decoder_seek_absolute(decoder,seekpos);
181*600f14f4SXin Li break;
182*600f14f4SXin Li case 8:
183*600f14f4SXin Li /* Set abort on write callback */
184*600f14f4SXin Li write_abort_check_counter = (command[0] >> 4) + 1;
185*600f14f4SXin Li break;
186*600f14f4SXin Li }
187*600f14f4SXin Li }
188*600f14f4SXin Li
189*600f14f4SXin Li FLAC__stream_decoder_finish(decoder);
190*600f14f4SXin Li
191*600f14f4SXin Li FLAC__stream_decoder_delete(decoder);
192*600f14f4SXin Li
193*600f14f4SXin Li return 0;
194*600f14f4SXin Li }
195*600f14f4SXin Li
196