Skip to content

Commit

Permalink
Fix misc issues due to OSS-fuzz (AcademySoftwareFoundation#1173)
Browse files Browse the repository at this point in the history
* Fix issues with fuzz test driver

- Adds a (disabled) error handler print to make th test cases easier to
part
- Fixes an initialization of buffers to use the better half
- mark a couple of functions internal (static)

Signed-off-by: Kimball Thurston <[email protected]>

* Add chunk for offsets in chunk table to be (somewhat validate)

Signed-off-by: Kimball Thurston <[email protected]>

* Clarify comment, simplify logic check

Signed-off-by: Kimball Thurston <[email protected]>

* Add check in mirror decode pipeline for alloc of 0 bytes

Signed-off-by: Kimball Thurston <[email protected]>

* Adjust logic so we can handle single scanline compression with image sampling

Signed-off-by: Kimball Thurston <[email protected]>

* switch to controlling prints for checking behind a getenv

Signed-off-by: Kimball Thurston <[email protected]>
  • Loading branch information
kdt3rd authored and cary-ilm committed Oct 13, 2021
1 parent a201460 commit 34a779e
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 25 deletions.
65 changes: 48 additions & 17 deletions src/lib/OpenEXRCore/chunk.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,17 +51,20 @@ static exr_result_t
extract_chunk_table (
const struct _internal_exr_context* ctxt,
const struct _internal_exr_part* part,
uint64_t** chunktable)
uint64_t** chunktable,
uint64_t* chunkminoffset)
{
uint64_t* ctable = NULL;
uint64_t* ctable = NULL;
uint64_t chunkoff = part->chunk_table_offset;
uint64_t chunkbytes = sizeof (uint64_t) * (uint64_t) part->chunk_count;

*chunkminoffset = chunkoff + chunkbytes;

ctable = (uint64_t*) atomic_load (
EXR_CONST_CAST (atomic_uintptr_t*, &(part->chunk_table)));
if (ctable == NULL)
{
uint64_t chunkoff = part->chunk_table_offset;
uint64_t chunkbytes = sizeof (uint64_t) * (uint64_t) part->chunk_count;
int64_t nread = 0;
int64_t nread = 0;
uintptr_t eptr = 0, nptr = 0;

exr_result_t rv;
Expand Down Expand Up @@ -198,7 +201,7 @@ exr_read_scanline_chunk_info (
int32_t data[3];
int64_t ddata[3];
int64_t fsize;
uint64_t dataoff;
uint64_t chunkmin, dataoff;
exr_attr_box2i_t dw;
uint64_t* ctable;
EXR_PROMOTE_READ_CONST_CONTEXT_AND_PART_OR_ERROR (ctxt, part_index);
Expand Down Expand Up @@ -263,10 +266,23 @@ exr_read_scanline_chunk_info (
cinfo->level_y = 0;

/* need to read from the file to get the packed chunk size */
rv = extract_chunk_table (pctxt, part, &ctable);
rv = extract_chunk_table (pctxt, part, &ctable, &chunkmin);
if (rv != EXR_ERR_SUCCESS) return rv;

fsize = pctxt->file_size;

dataoff = ctable[cidx];
if (dataoff < chunkmin || (fsize > 0 && dataoff > (uint64_t) fsize))
{
return pctxt->print_error (
pctxt,
EXR_ERR_BAD_CHUNK_LEADER,
"Corrupt chunk offset table: scanline %d, chunk index %d recorded at file offset %" PRIu64,
y,
cidx,
dataoff);
}

/* multi part files have the part for validation */
rdcnt = (pctxt->is_multipart) ? 2 : 1;
/* deep has 64-bit data, so be variable about what we read */
Expand Down Expand Up @@ -312,7 +328,6 @@ exr_read_scanline_chunk_info (
miny);
}

fsize = pctxt->file_size;
if (part->storage_mode == EXR_STORAGE_DEEP_SCANLINE)
{
rv = pctxt->do_read (
Expand Down Expand Up @@ -584,8 +599,8 @@ exr_read_tile_chunk_info (
int32_t data[6];
int32_t* tdata;
int32_t cidx, ntoread;
uint64_t dataoff;
int64_t fsize, tend, dend;
uint64_t chunkmin, dataoff;
int64_t nread, fsize, tend, dend;
const exr_attr_chlist_t* chanlist;
const exr_attr_tiledesc_t* tiledesc;
int tilew, tileh;
Expand Down Expand Up @@ -655,14 +670,15 @@ exr_read_tile_chunk_info (
cinfo->level_y = (uint8_t) levely;

chanlist = part->channels->chlist;
texels = (uint64_t) tilew * (uint64_t) tileh;
texels = (uint64_t) tilew * (uint64_t) tileh;
for (int c = 0; c < chanlist->num_channels; ++c)
{
const exr_attr_chlist_entry_t* curc = (chanlist->entries + c);
unpacksize += texels * (uint64_t) ((curc->pixel_type == EXR_PIXEL_HALF) ? 2 : 4);
unpacksize +=
texels * (uint64_t) ((curc->pixel_type == EXR_PIXEL_HALF) ? 2 : 4);
}

rv = extract_chunk_table (pctxt, part, &ctable);
rv = extract_chunk_table (pctxt, part, &ctable, &chunkmin);
if (rv != EXR_ERR_SUCCESS) return rv;

if (part->storage_mode == EXR_STORAGE_DEEP_TILED)
Expand All @@ -677,13 +693,29 @@ exr_read_tile_chunk_info (
else
ntoread = 5;

fsize = pctxt->file_size;

dataoff = ctable[cidx];
rv = pctxt->do_read (
if (dataoff < chunkmin || (fsize > 0 && dataoff > (uint64_t) fsize))
{
return pctxt->print_error (
pctxt,
EXR_ERR_BAD_CHUNK_LEADER,
"Corrupt chunk offset table: tile (%d, %d), level (%d, %d), chunk index %d recorded at file offset %" PRIu64,
tilex,
tiley,
levelx,
levely,
cidx,
dataoff);
}

rv = pctxt->do_read (
pctxt,
data,
(uint64_t) (ntoread) * sizeof (int32_t),
&dataoff,
&fsize,
&nread,
EXR_MUST_READ_ALL);
if (rv != EXR_ERR_SUCCESS)
{
Expand All @@ -698,7 +730,7 @@ exr_read_tile_chunk_info (
levely,
(uint64_t) (ntoread) * sizeof (int32_t),
ctable[cidx],
fsize);
(uint64_t) nread);
}
priv_to_native32 (data, ntoread);

Expand Down Expand Up @@ -778,7 +810,6 @@ exr_read_tile_chunk_info (
levely);
}

fsize = pctxt->file_size;
if (part->storage_mode == EXR_STORAGE_DEEP_TILED)
{
int64_t ddata[3];
Expand Down
9 changes: 9 additions & 0 deletions src/lib/OpenEXRCore/coding.c
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,15 @@ internal_decode_alloc_buffer (
size_t newsz)
{
void* curbuf = *buf;

/* We might have a zero size here due to y sampling on a scanline
* image where there is an attempt to read that portion of the
* image. Just shortcut here and handle at a higher level where
* there is more context
*/
if (newsz == 0)
return EXR_ERR_SUCCESS;

if (!curbuf || *cursz < newsz)
{
internal_decode_free_buffer (decode, bufid, buf, cursz);
Expand Down
4 changes: 2 additions & 2 deletions src/lib/OpenEXRCore/internal_huf.c
Original file line number Diff line number Diff line change
Expand Up @@ -796,7 +796,7 @@ hufDecode (
const uint8_t* in, // i : compressed input buffer
uint64_t ni, // i : input size (in bits)
uint32_t rlc, // i : run-length code
uint64_t no, // i : expected output size (in bytes)
uint64_t no, // i : expected output size (count of uint16 items)
uint16_t* out)
{
uint64_t c = 0;
Expand Down Expand Up @@ -894,7 +894,7 @@ hufDecode (
return EXR_ERR_CORRUPT_CHUNK;
}

if ((((uintptr_t) out) - ((uintptr_t) outb)) != no)
if (out != oe)
return EXR_ERR_OUT_OF_MEMORY;
return EXR_ERR_SUCCESS;
}
Expand Down
34 changes: 28 additions & 6 deletions src/lib/OpenEXRUtil/ImfCheckFile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@

#include <vector>
#include <algorithm>
#include <stdlib.h>

OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER

Expand Down Expand Up @@ -1349,10 +1350,10 @@ bool readCoreTiledPart(exr_context_t f, int part, bool reduceMemory, bool reduce
{
exr_coding_channel_info_t & outc = decoder.channels[c];
// fake addr for default rouines
outc.decode_to_ptr = (uint8_t*)0x1000;
outc.decode_to_ptr = (uint8_t*)0x1000 + bytes;
outc.user_pixel_stride = outc.user_bytes_per_element;
outc.user_line_stride = outc.user_pixel_stride * curtw;
bytes += curtw * (uint64_t)outc.user_bytes_per_element * (uint64_t)curth;
bytes += (uint64_t)curtw * (uint64_t)outc.user_bytes_per_element * (uint64_t)curth;
}

doread = true;
Expand Down Expand Up @@ -1390,8 +1391,8 @@ bool readCoreTiledPart(exr_context_t f, int part, bool reduceMemory, bool reduce
exr_coding_channel_info_t & outc = decoder.channels[c];
outc.decode_to_ptr = dptr;
outc.user_pixel_stride = outc.user_bytes_per_element;
outc.user_line_stride = outc.user_pixel_stride * curth;
dptr += curtw * (uint64_t)outc.user_bytes_per_element * (uint64_t)curth;
outc.user_line_stride = outc.user_pixel_stride * curtw;
dptr += (uint64_t)curtw * (uint64_t)outc.user_bytes_per_element * (uint64_t)curth;
}

rv = exr_decoding_run (f, part, &decoder);
Expand Down Expand Up @@ -1453,6 +1454,24 @@ bool checkCoreFile(exr_context_t f, bool reduceMemory, bool reduceTime)

////////////////////////////////////////

static void
core_error_handler_cb (exr_const_context_t f, int code, const char* msg)
{
if (getenv ("EXR_CHECK_ENABLE_PRINTS") != NULL)
{
const char* fn;
if (EXR_ERR_SUCCESS != exr_get_file_name (f, &fn)) fn = "<error>";
fprintf (
stderr,
"ERROR '%s' (%s): %s\n",
fn,
exr_get_error_code_as_string (code),
msg);
}
}

////////////////////////////////////////

bool
runCoreChecks (const char *filename, bool reduceMemory, bool reduceTime)
{
Expand All @@ -1461,6 +1480,8 @@ runCoreChecks (const char *filename, bool reduceMemory, bool reduceTime)
exr_context_t f;
exr_context_initializer_t cinit = EXR_DEFAULT_CONTEXT_INITIALIZER;

cinit.error_handler_fn = &core_error_handler_cb;

rv = exr_start_read (&f, filename, &cinit);
if (rv != EXR_ERR_SUCCESS)
return true;
Expand All @@ -1480,7 +1501,7 @@ struct memdata
size_t bytes;
};

int64_t
static int64_t
memstream_read (
exr_const_context_t f,
void* userdata,
Expand All @@ -1504,7 +1525,7 @@ memstream_read (
return rdsz;
}

int64_t memstream_size (
static int64_t memstream_size (
exr_const_context_t ctxt, void* userdata)
{
if (userdata)
Expand All @@ -1530,6 +1551,7 @@ runCoreChecks (const char *data, size_t numBytes, bool reduceMemory, bool reduce
cinit.user_data = &md;
cinit.read_fn = &memstream_read;
cinit.size_fn = &memstream_size;
cinit.error_handler_fn = &core_error_handler_cb;

rv = exr_start_read (&f, "<memstream>", &cinit);
if (rv != EXR_ERR_SUCCESS)
Expand Down

0 comments on commit 34a779e

Please sign in to comment.