• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2020 Google Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include <assert.h>
16 #include <string>
17 
18 #include "include/flac_parser.h"
19 
20 #include <jni.h>
21 
22 // #include <android/log.h>
23 
24 #include <cassert>
25 #include <cstdlib>
26 #include <cstring>
27 
28 #define LOG_TAG "FLACParser"
29 
30 #define LITERAL_TO_STRING_INTERNAL(x) #x
31 #define LITERAL_TO_STRING(x) LITERAL_TO_STRING_INTERNAL(x)
32 
33 #define CHECK(x) if (!(x)) return 0;
34 
35 const int endian = 1;
36 #define isBigEndian() (*(reinterpret_cast<const char *>(&endian)) == 0)
37 
38 // The FLAC parser calls our C++ static callbacks using C calling conventions,
39 // inside FLAC__stream_decoder_process_until_end_of_metadata
40 // and FLAC__stream_decoder_process_single.
41 // We immediately then call our corresponding C++ instance methods
42 // with the same parameter list, but discard redundant information.
43 
read_callback(const FLAC__StreamDecoder *,FLAC__byte buffer[],size_t * bytes,void * client_data)44 FLAC__StreamDecoderReadStatus FLACParser::read_callback(
45     const FLAC__StreamDecoder * /* decoder */, FLAC__byte buffer[],
46     size_t *bytes, void *client_data) {
47   return reinterpret_cast<FLACParser *>(client_data)
48       ->readCallback(buffer, bytes);
49 }
50 
seek_callback(const FLAC__StreamDecoder *,FLAC__uint64 absolute_byte_offset,void * client_data)51 FLAC__StreamDecoderSeekStatus FLACParser::seek_callback(
52     const FLAC__StreamDecoder * /* decoder */,
53     FLAC__uint64 absolute_byte_offset, void *client_data) {
54   return reinterpret_cast<FLACParser *>(client_data)
55       ->seekCallback(absolute_byte_offset);
56 }
57 
tell_callback(const FLAC__StreamDecoder *,FLAC__uint64 * absolute_byte_offset,void * client_data)58 FLAC__StreamDecoderTellStatus FLACParser::tell_callback(
59     const FLAC__StreamDecoder * /* decoder */,
60     FLAC__uint64 *absolute_byte_offset, void *client_data) {
61   return reinterpret_cast<FLACParser *>(client_data)
62       ->tellCallback(absolute_byte_offset);
63 }
64 
length_callback(const FLAC__StreamDecoder *,FLAC__uint64 * stream_length,void * client_data)65 FLAC__StreamDecoderLengthStatus FLACParser::length_callback(
66     const FLAC__StreamDecoder * /* decoder */, FLAC__uint64 *stream_length,
67     void *client_data) {
68   return reinterpret_cast<FLACParser *>(client_data)
69       ->lengthCallback(stream_length);
70 }
71 
eof_callback(const FLAC__StreamDecoder *,void * client_data)72 FLAC__bool FLACParser::eof_callback(const FLAC__StreamDecoder * /* decoder */,
73                                     void *client_data) {
74   return reinterpret_cast<FLACParser *>(client_data)->eofCallback();
75 }
76 
write_callback(const FLAC__StreamDecoder *,const FLAC__Frame * frame,const FLAC__int32 * const buffer[],void * client_data)77 FLAC__StreamDecoderWriteStatus FLACParser::write_callback(
78     const FLAC__StreamDecoder * /* decoder */, const FLAC__Frame *frame,
79     const FLAC__int32 *const buffer[], void *client_data) {
80   return reinterpret_cast<FLACParser *>(client_data)
81       ->writeCallback(frame, buffer);
82 }
83 
metadata_callback(const FLAC__StreamDecoder *,const FLAC__StreamMetadata * metadata,void * client_data)84 void FLACParser::metadata_callback(const FLAC__StreamDecoder * /* decoder */,
85                                    const FLAC__StreamMetadata *metadata,
86                                    void *client_data) {
87   reinterpret_cast<FLACParser *>(client_data)->metadataCallback(metadata);
88 }
89 
error_callback(const FLAC__StreamDecoder *,FLAC__StreamDecoderErrorStatus status,void * client_data)90 void FLACParser::error_callback(const FLAC__StreamDecoder * /* decoder */,
91                                 FLAC__StreamDecoderErrorStatus status,
92                                 void *client_data) {
93   reinterpret_cast<FLACParser *>(client_data)->errorCallback(status);
94 }
95 
96 // These are the corresponding callbacks with C++ calling conventions
97 
readCallback(FLAC__byte buffer[],size_t * bytes)98 FLAC__StreamDecoderReadStatus FLACParser::readCallback(FLAC__byte buffer[],
99                                                        size_t *bytes) {
100   size_t requested = *bytes;
101   ssize_t actual = mDataSource->readAt(mCurrentPos, buffer, requested);
102   if (0 > actual) {
103     *bytes = 0;
104     return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
105   } else if (0 == actual) {
106     *bytes = 0;
107     mEOF = true;
108     return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
109   } else {
110     assert(actual <= requested);
111     *bytes = actual;
112     mCurrentPos += actual;
113     return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
114   }
115 }
116 
seekCallback(FLAC__uint64 absolute_byte_offset)117 FLAC__StreamDecoderSeekStatus FLACParser::seekCallback(
118     FLAC__uint64 absolute_byte_offset) {
119   mCurrentPos = absolute_byte_offset;
120   mEOF = false;
121   return FLAC__STREAM_DECODER_SEEK_STATUS_OK;
122 }
123 
tellCallback(FLAC__uint64 * absolute_byte_offset)124 FLAC__StreamDecoderTellStatus FLACParser::tellCallback(
125     FLAC__uint64 *absolute_byte_offset) {
126   *absolute_byte_offset = mCurrentPos;
127   return FLAC__STREAM_DECODER_TELL_STATUS_OK;
128 }
129 
lengthCallback(FLAC__uint64 * stream_length)130 FLAC__StreamDecoderLengthStatus FLACParser::lengthCallback(
131     FLAC__uint64 *stream_length) {
132   return FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED;
133 }
134 
eofCallback()135 FLAC__bool FLACParser::eofCallback() { return mEOF; }
136 
writeCallback(const FLAC__Frame * frame,const FLAC__int32 * const buffer[])137 FLAC__StreamDecoderWriteStatus FLACParser::writeCallback(
138     const FLAC__Frame *frame, const FLAC__int32 *const buffer[]) {
139   if (mWriteRequested) {
140     mWriteRequested = false;
141     // FLAC parser doesn't free or realloc buffer until next frame or finish
142     mWriteHeader = frame->header;
143     mWriteBuffer = buffer;
144     mWriteCompleted = true;
145     return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
146   } else {
147     return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
148   }
149 }
150 
metadataCallback(const FLAC__StreamMetadata * metadata)151 void FLACParser::metadataCallback(const FLAC__StreamMetadata *metadata) {
152   switch (metadata->type) {
153     case FLAC__METADATA_TYPE_STREAMINFO:
154       if (!mStreamInfoValid) {
155         mStreamInfo = metadata->data.stream_info;
156         mStreamInfoValid = true;
157       } else {
158         break;
159       }
160       break;
161     case FLAC__METADATA_TYPE_SEEKTABLE:
162       mSeekTable = &metadata->data.seek_table;
163       break;
164     case FLAC__METADATA_TYPE_VORBIS_COMMENT:
165       if (!mVorbisCommentsValid) {
166         FLAC__StreamMetadata_VorbisComment vorbisComment =
167             metadata->data.vorbis_comment;
168         for (FLAC__uint32 i = 0; i < vorbisComment.num_comments; ++i) {
169           FLAC__StreamMetadata_VorbisComment_Entry vorbisCommentEntry =
170               vorbisComment.comments[i];
171           if (vorbisCommentEntry.entry != NULL) {
172             std::string comment(
173                 reinterpret_cast<char *>(vorbisCommentEntry.entry),
174                 vorbisCommentEntry.length);
175             mVorbisComments.push_back(comment);
176           }
177         }
178         mVorbisCommentsValid = true;
179       } else {
180         break;
181       }
182       break;
183     case FLAC__METADATA_TYPE_PICTURE: {
184       const FLAC__StreamMetadata_Picture *parsedPicture =
185           &metadata->data.picture;
186       FlacPicture picture;
187       picture.mimeType.assign(std::string(parsedPicture->mime_type));
188       picture.description.assign(
189           std::string((char *)parsedPicture->description));
190       picture.data.assign(parsedPicture->data,
191                           parsedPicture->data + parsedPicture->data_length);
192       picture.width = parsedPicture->width;
193       picture.height = parsedPicture->height;
194       picture.depth = parsedPicture->depth;
195       picture.colors = parsedPicture->colors;
196       picture.type = parsedPicture->type;
197       mPictures.push_back(picture);
198       mPicturesValid = true;
199       break;
200     }
201     default:
202       break;
203   }
204 }
205 
errorCallback(FLAC__StreamDecoderErrorStatus status)206 void FLACParser::errorCallback(FLAC__StreamDecoderErrorStatus status) {
207   mErrorStatus = status;
208 }
209 
210 // Copy samples from FLAC native 32-bit non-interleaved to
211 // correct bit-depth (non-zero padded), interleaved.
212 // These are candidates for optimization if needed.
copyToByteArrayBigEndian(int8_t * dst,const int * const * src,unsigned bytesPerSample,unsigned nSamples,unsigned nChannels)213 static void copyToByteArrayBigEndian(int8_t *dst, const int *const *src,
214                                      unsigned bytesPerSample, unsigned nSamples,
215                                      unsigned nChannels) {
216   for (unsigned i = 0; i < nSamples; ++i) {
217     for (unsigned c = 0; c < nChannels; ++c) {
218       // point to the first byte of the source address
219       // and then skip the first few bytes (most significant bytes)
220       // depending on the bit depth
221       const int8_t *byteSrc =
222           reinterpret_cast<const int8_t *>(&src[c][i]) + 4 - bytesPerSample;
223       memcpy(dst, byteSrc, bytesPerSample);
224       dst = dst + bytesPerSample;
225     }
226   }
227 }
228 
copyToByteArrayLittleEndian(int8_t * dst,const int * const * src,unsigned bytesPerSample,unsigned nSamples,unsigned nChannels)229 static void copyToByteArrayLittleEndian(int8_t *dst, const int *const *src,
230                                         unsigned bytesPerSample,
231                                         unsigned nSamples, unsigned nChannels) {
232   for (unsigned i = 0; i < nSamples; ++i) {
233     for (unsigned c = 0; c < nChannels; ++c) {
234       // with little endian, the most significant bytes will be at the end
235       // copy the bytes in little endian will remove the most significant byte
236       // so we are good here.
237       memcpy(dst, &(src[c][i]), bytesPerSample);
238       dst = dst + bytesPerSample;
239     }
240   }
241 }
242 
copyTrespass(int8_t *,const int * const *,unsigned,unsigned,unsigned)243 static void copyTrespass(int8_t * /* dst */, const int *const * /* src */,
244                          unsigned /* bytesPerSample */, unsigned /* nSamples */,
245                          unsigned /* nChannels */) {
246   ;
247 }
248 
249 // FLACParser
250 
FLACParser(DataSource * source)251 FLACParser::FLACParser(DataSource *source)
252     : mDataSource(source),
253       mCopy(copyTrespass),
254       mDecoder(NULL),
255       mCurrentPos(0LL),
256       mEOF(false),
257       mStreamInfoValid(false),
258       mSeekTable(NULL),
259       firstFrameOffset(0LL),
260       mVorbisCommentsValid(false),
261       mPicturesValid(false),
262       mWriteRequested(false),
263       mWriteCompleted(false),
264       mWriteBuffer(NULL),
265       mErrorStatus((FLAC__StreamDecoderErrorStatus)-1) {
266   memset(&mStreamInfo, 0, sizeof(mStreamInfo));
267   memset(&mWriteHeader, 0, sizeof(mWriteHeader));
268 }
269 
~FLACParser()270 FLACParser::~FLACParser() {
271   if (mDecoder != NULL) {
272     FLAC__stream_decoder_delete(mDecoder);
273     mDecoder = NULL;
274   }
275 }
276 
init()277 bool FLACParser::init() {
278   // setup libFLAC parser
279   mDecoder = FLAC__stream_decoder_new();
280   if (mDecoder == NULL) {
281     // The new should succeed, since probably all it does is a malloc
282     // that always succeeds in Android.  But to avoid dependence on the
283     // libFLAC internals, we check and log here.
284     return false;
285   }
286   FLAC__stream_decoder_set_md5_checking(mDecoder, false);
287   FLAC__stream_decoder_set_metadata_ignore_all(mDecoder);
288   FLAC__stream_decoder_set_metadata_respond(mDecoder,
289                                             FLAC__METADATA_TYPE_STREAMINFO);
290   FLAC__stream_decoder_set_metadata_respond(mDecoder,
291                                             FLAC__METADATA_TYPE_SEEKTABLE);
292   FLAC__stream_decoder_set_metadata_respond(mDecoder,
293                                             FLAC__METADATA_TYPE_VORBIS_COMMENT);
294   FLAC__stream_decoder_set_metadata_respond(mDecoder,
295                                             FLAC__METADATA_TYPE_PICTURE);
296   FLAC__StreamDecoderInitStatus initStatus;
297   initStatus = FLAC__stream_decoder_init_stream(
298       mDecoder, read_callback, seek_callback, tell_callback, length_callback,
299       eof_callback, write_callback, metadata_callback, error_callback,
300       reinterpret_cast<void *>(this));
301   if (initStatus != FLAC__STREAM_DECODER_INIT_STATUS_OK) {
302     // A failure here probably indicates a programming error and so is
303     // unlikely to happen. But we check and log here similarly to above.
304     return false;
305   }
306   return true;
307 }
308 
decodeMetadata()309 bool FLACParser::decodeMetadata() {
310   // parse all metadata
311   if (!FLAC__stream_decoder_process_until_end_of_metadata(mDecoder)) {
312     return false;
313   }
314   // store first frame offset
315   FLAC__stream_decoder_get_decode_position(mDecoder, &firstFrameOffset);
316 
317   if (mStreamInfoValid) {
318     // check channel count
319     if (getChannels() == 0 || getChannels() > 8) {
320       return false;
321     }
322     // check bit depth
323     switch (getBitsPerSample()) {
324       case 8:
325       case 16:
326       case 24:
327       case 32:
328         break;
329       default:
330         return false;
331     }
332     // configure the appropriate copy function based on device endianness.
333     if (isBigEndian()) {
334       mCopy = copyToByteArrayBigEndian;
335     } else {
336       mCopy = copyToByteArrayLittleEndian;
337     }
338   } else {
339     return false;
340   }
341   return true;
342 }
343 
readBuffer(void * output,size_t output_size)344 size_t FLACParser::readBuffer(void *output, size_t output_size) {
345   mWriteRequested = true;
346   mWriteCompleted = false;
347 
348   if (!FLAC__stream_decoder_process_single(mDecoder)) {
349     return -1;
350   }
351   if (!mWriteCompleted) {
352     if (FLAC__stream_decoder_get_state(mDecoder) !=
353         FLAC__STREAM_DECODER_END_OF_STREAM) {
354     }
355     return -1;
356   }
357 
358   // verify that block header keeps the promises made by STREAMINFO
359   unsigned blocksize = mWriteHeader.blocksize;
360   if (blocksize == 0 || blocksize > getMaxBlockSize()) {
361     return -1;
362   }
363   if (mWriteHeader.sample_rate != getSampleRate() ||
364       mWriteHeader.channels != getChannels() ||
365       mWriteHeader.bits_per_sample != getBitsPerSample()) {
366     return -1;
367   }
368 
369   unsigned bytesPerSample = getBitsPerSample() >> 3;
370   size_t bufferSize = blocksize * getChannels() * bytesPerSample;
371   if (bufferSize > output_size) {
372     return -1;
373   }
374 
375   // copy PCM from FLAC write buffer to our media buffer, with interleaving.
376   (*mCopy)(reinterpret_cast<int8_t *>(output), mWriteBuffer, bytesPerSample,
377            blocksize, getChannels());
378 
379   // fill in buffer metadata
380   CHECK(mWriteHeader.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER);
381 
382   return bufferSize;
383 }
384 
getSeekPositions(int64_t timeUs,std::array<int64_t,4> & result)385 bool FLACParser::getSeekPositions(int64_t timeUs,
386                                   std::array<int64_t, 4> &result) {
387   if (!mSeekTable) {
388     return false;
389   }
390 
391   unsigned sampleRate = getSampleRate();
392   int64_t totalSamples = getTotalSamples();
393   int64_t targetSampleNumber = (timeUs * sampleRate) / 1000000LL;
394   if (targetSampleNumber >= totalSamples) {
395     targetSampleNumber = totalSamples - 1;
396   }
397 
398   FLAC__StreamMetadata_SeekPoint* points = mSeekTable->points;
399   unsigned length = mSeekTable->num_points;
400 
401   for (unsigned i = length; i != 0; i--) {
402     int64_t sampleNumber = points[i - 1].sample_number;
403     if (sampleNumber == -1) {  // placeholder
404       continue;
405     }
406     if (sampleNumber <= targetSampleNumber) {
407       result[0] = (sampleNumber * 1000000LL) / sampleRate;
408       result[1] = firstFrameOffset + points[i - 1].stream_offset;
409       if (sampleNumber == targetSampleNumber || i >= length ||
410           points[i].sample_number == -1) {  // placeholder
411         // exact seek, or no following non-placeholder seek point
412         result[2] = result[0];
413         result[3] = result[1];
414       } else {
415         result[2] = (points[i].sample_number * 1000000LL) / sampleRate;
416         result[3] = firstFrameOffset + points[i].stream_offset;
417       }
418       return true;
419     }
420   }
421   result[0] = 0;
422   result[1] = firstFrameOffset;
423   result[2] = 0;
424   result[3] = firstFrameOffset;
425   return true;
426 }
427 
428 namespace {
429 
430   class FuzzDataSource : public DataSource {
431     const uint8_t *data_;
432     size_t size_;
433 
434    public:
FuzzDataSource(const uint8_t * data,size_t size)435     FuzzDataSource(const uint8_t *data, size_t size) {
436       data_ = data;
437       size_ = size;
438     }
439 
readAt(off64_t offset,void * const data,size_t size)440     ssize_t readAt(off64_t offset, void *const data, size_t size) {
441       if (offset > size_)
442         return -1;
443       size_t remaining = size_ - offset;
444       if (remaining < size)
445         size = remaining;
446       memcpy(data, data_ + offset, size);
447       return size;
448     }
449   };
450 
451 }  // namespace
452 
453 // Fuzz FLAC format and instrument the result as exoplayer JNI would:
454 // https://github.com/google/ExoPlayer/blob/release-v2/extensions/flac/src/main/jni/
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)455 extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
456   FuzzDataSource source(data, size);
457   FLACParser parser(&source);
458 
459   // Early parsing
460   if (!parser.init() || !parser.decodeMetadata())
461     return 0;
462 
463   auto streamInfo = parser.getStreamInfo();
464 
465   // Similar implementation than ExoPlayer
466   int buffer_size = streamInfo.max_blocksize * streamInfo.channels * 2;
467   assert(buffer_size >= 0);  // Not expected
468   auto buffer = new uint8_t[buffer_size];
469   int runs = 0;
470   while (parser.readBuffer(buffer, buffer_size) >= buffer_size) {
471     runs++;
472     continue;
473   }
474   delete[] buffer;
475 
476   return 0;
477 }
478