Add new fuzzer for OSS-Fuzz (#769)

Adds a fuzzer targeting sf_read_double, sf_read_int and sf_read_short.

Co-authored-by: evpobr <evpobr@gmail.com>
This commit is contained in:
DavidKorczynski 2021-08-15 05:38:48 +01:00 committed by GitHub
parent dc1c8c2492
commit 110e26d9c2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 228 additions and 138 deletions

View File

@ -30,6 +30,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
* ID3v1 reading * ID3v1 reading
* ID3v2 reading * ID3v2 reading
* Seeking * Seeking
* New fuzzer for OSS-Fuzz, thanks @DavidKorczynski.
* This `CHANGELOG.md`. All notable changes to this project will be documented in * This `CHANGELOG.md`. All notable changes to this project will be documented in
this file. The old `NEWS` file has been renamed to `NEWS.OLD` and is no longer this file. The old `NEWS` file has been renamed to `NEWS.OLD` and is no longer
updated. updated.

View File

@ -462,7 +462,8 @@ endif
if USE_OSSFUZZERS if USE_OSSFUZZERS
noinst_PROGRAMS += \ noinst_PROGRAMS += \
ossfuzz/sndfile_fuzzer ossfuzz/sndfile_fuzzer \
ossfuzz/sndfile_alt_fuzzer
noinst_LTLIBRARIES += \ noinst_LTLIBRARIES += \
ossfuzz/libstandaloneengine.la ossfuzz/libstandaloneengine.la
@ -473,6 +474,11 @@ ossfuzz_sndfile_fuzzer_CXXFLAGS = $(AM_CXXFLAGS) $(FUZZ_FLAG)
ossfuzz_sndfile_fuzzer_LDFLAGS = $(AM_LDFLAGS) -static ossfuzz_sndfile_fuzzer_LDFLAGS = $(AM_LDFLAGS) -static
ossfuzz_sndfile_fuzzer_LDADD = src/libsndfile.la $(FUZZ_LDADD) ossfuzz_sndfile_fuzzer_LDADD = src/libsndfile.la $(FUZZ_LDADD)
ossfuzz_sndfile_alt_fuzzer_SOURCES = ossfuzz/sndfile_alt_fuzzer.cc
ossfuzz_sndfile_alt_fuzzer_CXXFLAGS = $(AM_CXXFLAGS) $(FUZZ_FLAG)
ossfuzz_sndfile_alt_fuzzer_LDFLAGS = $(AM_LDFLAGS) -static
ossfuzz_sndfile_alt_fuzzer_LDADD = src/libsndfile.la $(FUZZ_LDADD)
ossfuzz_libstandaloneengine_la_SOURCES = ossfuzz/standaloneengine.cc ossfuzz/testinput.h ossfuzz_libstandaloneengine_la_SOURCES = ossfuzz/standaloneengine.cc ossfuzz/testinput.h
ossfuzz_libstandaloneengine_la_CXXFLAGS = $(AM_CXXFLAGS) ossfuzz_libstandaloneengine_la_CXXFLAGS = $(AM_CXXFLAGS)

View File

@ -29,3 +29,4 @@ make V=1
# Copy the fuzzer to the output directory. # Copy the fuzzer to the output directory.
cp -v ossfuzz/sndfile_fuzzer $OUT/ cp -v ossfuzz/sndfile_fuzzer $OUT/
cp -v ossfuzz/sndfile_alt_fuzzer $OUT/

View File

@ -0,0 +1,79 @@
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sndfile.h>
#include <inttypes.h>
#include "sndfile_fuzz_header.h"
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
{ // One byte is needed for deciding which function to target.
if (size == 0)
return 0 ;
const uint8_t decider = *data ;
data += 1 ;
size -= 1 ;
SF_INFO sndfile_info ;
VIO_DATA vio_data ;
SF_VIRTUAL_IO vio ;
SNDFILE *sndfile = NULL ;
int err = sf_init_file(data, size, &sndfile, &vio_data, &vio, &sndfile_info) ;
if (err)
goto EXIT_LABEL ;
// Just the right number of channels. Create some buffer space for reading.
switch (decider % 3)
{ case 0 :
{
short* read_buffer = NULL ;
read_buffer = (short*)malloc(sizeof(short) * size);
if (read_buffer == NULL)
abort() ;
while (sf_read_short(sndfile, read_buffer, size))
{
// Do nothing with the data.
}
free(read_buffer) ;
}
break ;
case 1 :
{
int* read_buffer = NULL ;
read_buffer = (int*)malloc(sizeof(int) * size) ;
if (read_buffer == NULL)
abort() ;
while (sf_read_int(sndfile, read_buffer, size))
{
// Do nothing with the data.
}
free(read_buffer) ;
}
break ;
case 2 :
{
double* read_buffer = NULL ;
read_buffer = (double*)malloc(sizeof(double) * size) ;
if (read_buffer == NULL)
abort() ;
while (sf_read_double(sndfile, read_buffer, size))
{
// Do nothing with the data.
}
free(read_buffer) ;
}
break ;
default :
break ;
} ;
EXIT_LABEL:
if (sndfile != NULL)
sf_close(sndfile);
return 0 ;
}

View File

@ -0,0 +1,119 @@
#ifndef SNDFILE_FUZZ_HEADER_H
#define SNDFILE_FUZZ_HEADER_H
typedef struct
{
sf_count_t offset ;
sf_count_t length ;
const unsigned char *data ;
} VIO_DATA ;
static sf_count_t vfget_filelen (void *user_data)
{ VIO_DATA *vf = (VIO_DATA *)user_data ;
return vf->length ;
}
static sf_count_t vfseek (sf_count_t offset, int whence, void *user_data)
{
VIO_DATA *vf = (VIO_DATA *)user_data ;
sf_count_t new_offset ;
switch (whence)
{ case SEEK_SET :
new_offset = offset ;
break ;
case SEEK_CUR :
new_offset = vf->offset + offset ;
break ;
case SEEK_END :
new_offset = vf->length + offset ;
break ;
default :
break ;
}
/* Ensure you can't seek outside the data */
if (new_offset > vf->length)
{ /* Trying to seek past the end of the data */
printf("vf overseek: new_offset(%" PRId64 ") > vf->length(%" PRId64 ");"
" whence(%d), vf->offset(%" PRId64 "), offset(%" PRId64 ")\n",
new_offset, vf->length, whence, vf->offset, offset) ;
new_offset = vf->length ;
}
else if (new_offset < 0)
{ /* Trying to seek before the start of the data */
printf("vf underseek: new_offset(%" PRId64 ") < 0; whence(%d), vf->offset"
"(%" PRId64 "), vf->length(%" PRId64 "), offset(%" PRId64 ")\n",
new_offset, whence, vf->offset, vf->length, offset) ;
new_offset = 0 ;
}
vf->offset = new_offset ;
return vf->offset ;
}
static sf_count_t vfread (void *ptr, sf_count_t count, void *user_data)
{ VIO_DATA *vf = (VIO_DATA *)user_data ;
if (vf->offset + count > vf->length)
count = vf->length - vf->offset ;
memcpy(ptr, vf->data + vf->offset, count) ;
vf->offset += count ;
return count ;
}
static sf_count_t vfwrite (const void *ptr, sf_count_t count, void *user_data)
{
(void)ptr ;
(void)count ;
(void)user_data ;
// Cannot write to this virtual file.
return 0;
}
static sf_count_t vftell (void *user_data)
{ VIO_DATA *vf = (VIO_DATA *)user_data ;
return vf->offset ;
}
int sf_init_file(const uint8_t *data,
size_t size,
SNDFILE **sndfile,
VIO_DATA *vio_data,
SF_VIRTUAL_IO *vio, SF_INFO *sndfile_info)
{ float* read_buffer = NULL ;
// Initialize the virtual IO structure.
vio->get_filelen = vfget_filelen ;
vio->seek = vfseek ;
vio->read = vfread ;
vio->write = vfwrite ;
vio->tell = vftell ;
// Initialize the VIO user data.
vio_data->data = data ;
vio_data->length = size ;
vio_data->offset = 0 ;
memset(sndfile_info, 0, sizeof(SF_INFO)) ;
// Try and open the virtual file.
*sndfile = sf_open_virtual(vio, SFM_READ, sndfile_info, vio_data) ;
if (sndfile_info->channels == 0)
return -1 ;
if (sndfile_info->channels > 1024 * 1024)
return -1 ;
return 0;
}
#endif

View File

@ -5,151 +5,35 @@
#include <sndfile.h> #include <sndfile.h>
#include <inttypes.h> #include <inttypes.h>
typedef struct #include "sndfile_fuzz_header.h"
{
sf_count_t offset;
sf_count_t length;
const unsigned char *data;
} VIO_DATA;
static sf_count_t vfget_filelen (void *user_data)
{
VIO_DATA *vf = (VIO_DATA *)user_data;
return vf->length;
}
static sf_count_t vfseek (sf_count_t offset, int whence, void *user_data)
{
VIO_DATA *vf = (VIO_DATA *)user_data;
sf_count_t new_offset;
switch (whence)
{
case SEEK_SET:
new_offset = offset;
break ;
case SEEK_CUR:
new_offset = vf->offset + offset;
break ;
case SEEK_END:
new_offset = vf->length + offset;
break;
default:
break;
}
/* Ensure you can't seek outside the data */
if (new_offset > vf->length)
{
/* Trying to seek past the end of the data */
printf("vf overseek: new_offset(%" PRId64 ") > vf->length(%" PRId64 ");"
" whence(%d), vf->offset(%" PRId64 "), offset(%" PRId64 ")\n",
new_offset, vf->length, whence, vf->offset, offset);
new_offset = vf->length;
}
else if (new_offset < 0)
{
/* Trying to seek before the start of the data */
printf("vf underseek: new_offset(%" PRId64 ") < 0; whence(%d), vf->offset"
"(%" PRId64 "), vf->length(%" PRId64 "), offset(%" PRId64 ")\n",
new_offset, whence, vf->offset, vf->length, offset);
new_offset = 0;
}
vf->offset = new_offset;
return vf->offset;
}
static sf_count_t vfread (void *ptr, sf_count_t count, void *user_data)
{
VIO_DATA *vf = (VIO_DATA *)user_data;
if (vf->offset + count > vf->length)
{
count = vf->length - vf->offset;
}
memcpy(ptr, vf->data + vf->offset, count);
vf->offset += count;
return count;
}
static sf_count_t vfwrite (const void *ptr, sf_count_t count, void *user_data)
{
(void)ptr;
(void)count;
(void)user_data;
// Cannot write to this virtual file.
return 0;
}
static sf_count_t vftell (void *user_data)
{ VIO_DATA *vf = (VIO_DATA *)user_data;
return vf->offset;
}
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
{ { VIO_DATA vio_data ;
VIO_DATA vio_data; SF_VIRTUAL_IO vio ;
SF_VIRTUAL_IO vio; SF_INFO sndfile_info ;
SF_INFO sndfile_info; SNDFILE *sndfile = NULL ;
SNDFILE *sndfile = NULL; float* read_buffer = NULL ;
float* read_buffer = NULL;
// Initialize the virtual IO structure. int err = sf_init_file(data, size, &sndfile, &vio_data, &vio, &sndfile_info) ;
vio.get_filelen = vfget_filelen; if (err)
vio.seek = vfseek; goto EXIT_LABEL ;
vio.read = vfread;
vio.write = vfwrite;
vio.tell = vftell;
// Initialize the VIO user data. // Just the right number of channels. Create some buffer space for reading.
vio_data.data = data; read_buffer = (float*)malloc(sizeof(float) * sndfile_info.channels);
vio_data.length = size; if (read_buffer == NULL)
vio_data.offset = 0; abort() ;
memset(&sndfile_info, 0, sizeof(SF_INFO)); while (sf_readf_float(sndfile, read_buffer, 1))
{
// Try and open the virtual file. // Do nothing with the data.
sndfile = sf_open_virtual(&vio, SFM_READ, &sndfile_info, &vio_data); }
if (sndfile_info.channels == 0)
{
// No sound channels in file.
goto EXIT_LABEL;
}
else if (sndfile_info.channels > 1024 * 1024)
{
// Too many channels to handle.
goto EXIT_LABEL;
}
// Just the right number of channels. Create some buffer space for reading.
read_buffer = (float*)malloc(sizeof(float) * sndfile_info.channels);
if (read_buffer == NULL)
{
abort();
}
while (sf_readf_float(sndfile, read_buffer, 1))
{
// Do nothing with the data.
}
EXIT_LABEL: EXIT_LABEL:
if (sndfile != NULL) if (sndfile != NULL)
{ sf_close(sndfile) ;
sf_close(sndfile);
}
free(read_buffer); free(read_buffer) ;
return 0; return 0 ;
} }