Coverage Report

Created: 2023-06-29 06:15

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