Skip to content

Commit

Permalink
Address OSS Fuzz Issues (#1268)
Browse files Browse the repository at this point in the history
* Add utility function header

Add location to extract internal helper functions to reduce code
duplication

Signed-off-by: Kimball Thurston <kdt3rd@gmail.com>

* Fix issues with odd y_sampling numbers

Use new compute_sampled_lines when the y_sampling is odd (sampling % 2
== 1), where the number of lines per chunk will oscillate.

Signed-off-by: Kimball Thurston <kdt3rd@gmail.com>

* Fix integer overflow computing deep chunk index

Signed-off-by: Kimball Thurston <kdt3rd@gmail.com>

* Fix decompression scratch buffer size

Use a minimum size to handle that b44 is always 4x4 blocks

Signed-off-by: Kimball Thurston <kdt3rd@gmail.com>

* Use appropriate buffer size when decompressing

use the scratch buffer size instead of decompressed buffer size, allow
some extra padding in scratch buffer when appropriate

Signed-off-by: Kimball Thurston <kdt3rd@gmail.com>
  • Loading branch information
kdt3rd committed Jul 31, 2022
1 parent c5763cf commit 7629dad
Show file tree
Hide file tree
Showing 5 changed files with 116 additions and 70 deletions.
74 changes: 32 additions & 42 deletions src/lib/OpenEXRCore/chunk.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

#include "internal_coding.h"
#include "internal_structs.h"
#include "internal_util.h"
#include "internal_xdr.h"

#include <limits.h>
Expand Down Expand Up @@ -408,8 +409,21 @@ read_and_validate_chunk_leader (
if (part->storage_mode == EXR_STORAGE_SCANLINE ||
part->storage_mode == EXR_STORAGE_DEEP_SCANLINE)
{
*indexio = (leader.scanline_y - part->data_window.min.y) /
part->lines_per_chunk;
int64_t chunk = (int64_t) leader.scanline_y;
chunk -= (int64_t) part->data_window.min.y;
chunk /= part->lines_per_chunk;
if (chunk < 0 || chunk > INT32_MAX)
return ctxt->print_error (
ctxt,
EXR_ERR_BAD_CHUNK_LEADER,
"Invalid chunk index: %" PRId64
" reading scanline %d (datawindow min %d) with lines per chunk %d",
chunk,
leader.scanline_y,
part->data_window.min.y,
part->lines_per_chunk);

*indexio = (int) chunk;
}
else
{
Expand Down Expand Up @@ -527,10 +541,10 @@ extract_chunk_table (
EXR_CONST_CAST (atomic_uintptr_t*, &(part->chunk_table)));
if (ctable == NULL)
{
int64_t nread = 0;
uintptr_t eptr = 0, nptr = 0;
int complete = 1;
uint64_t maxoff = ((uint64_t) -1);
int64_t nread = 0;
uintptr_t eptr = 0, nptr = 0;
int complete = 1;
uint64_t maxoff = ((uint64_t) -1);
exr_result_t rv;

if (part->chunk_count <= 0)
Expand Down Expand Up @@ -590,10 +604,7 @@ extract_chunk_table (
}
}
}
else
{
priv_to_native64 (ctable, part->chunk_count);
}
else { priv_to_native64 (ctable, part->chunk_count); }

nptr = (uintptr_t) ctable;
// see if we win or not
Expand Down Expand Up @@ -670,21 +681,11 @@ compute_chunk_unpack_size (
{
const exr_attr_chlist_entry_t* curc = (chanlist->entries + c);
uint64_t chansz = ((curc->pixel_type == EXR_PIXEL_HALF) ? 2 : 4);
chansz *= ((uint64_t) width);

chansz *= (uint64_t) width;
if (curc->x_sampling > 1) chansz /= ((uint64_t) curc->x_sampling);
chansz *= ((uint64_t) height);
if (curc->y_sampling > 1)
{
if (height > 1)
{
if (curc->y_sampling > height)
chansz /= ((uint64_t) height);
else
chansz /= ((uint64_t) curc->y_sampling);
}
else if ((y % ((int) curc->y_sampling)) != 0)
chansz = 0;
}
chansz *=
(uint64_t) compute_sampled_lines (height, curc->y_sampling, y);
unpacksize += chansz;
}
}
Expand Down Expand Up @@ -761,10 +762,7 @@ exr_read_scanline_chunk_info (
cinfo->start_y = dw.min.y;
cinfo->height -= (dw.min.y - miny);
}
else if ((miny + lpc) > dw.max.y)
{
cinfo->height = (dw.max.y - miny + 1);
}
else if ((miny + lpc) > dw.max.y) { cinfo->height = (dw.max.y - miny + 1); }
cinfo->level_x = 0;
cinfo->level_y = 0;

Expand Down Expand Up @@ -932,10 +930,11 @@ exr_read_scanline_chunk_info (
pctxt,
EXR_ERR_BAD_CHUNK_LEADER,
"Preparing to read scanline %d (chunk %d), found corrupt leader: packed size %" PRIu64
", file size %" PRId64,
", file offset %" PRIu64 ", size %" PRId64,
y,
cidx,
(uint64_t) data[rdcnt],
cinfo->packed_size,
cinfo->data_offset,
fsize);
}
}
Expand Down Expand Up @@ -1637,10 +1636,7 @@ write_scan_chunk (
/* just in case we look at it again? */
priv_to_native64 (ctable, part->chunk_count);
}
else
{
pctxt->last_output_chunk = cidx;
}
else { pctxt->last_output_chunk = cidx; }
}

return rv;
Expand Down Expand Up @@ -1722,10 +1718,7 @@ exr_write_scanline_chunk_info (
cinfo->start_y = dw.min.y;
cinfo->height -= (dw.min.y - miny);
}
else if ((miny + lpc) > dw.max.y)
{
cinfo->height = (dw.max.y - miny + 1);
}
else if ((miny + lpc) > dw.max.y) { cinfo->height = (dw.max.y - miny + 1); }
cinfo->level_x = 0;
cinfo->level_y = 0;

Expand Down Expand Up @@ -2060,10 +2053,7 @@ write_tile_chunk (
/* just in case we look at it again? */
priv_to_native64 (ctable, part->chunk_count);
}
else
{
pctxt->last_output_chunk = cidx;
}
else { pctxt->last_output_chunk = cidx; }
}

return rv;
Expand Down
25 changes: 5 additions & 20 deletions src/lib/OpenEXRCore/coding.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
*/

#include "internal_coding.h"
#include "internal_util.h"

#include <string.h>

Expand Down Expand Up @@ -40,16 +41,8 @@ internal_coding_fill_channel_info (

decc->channel_name = curc->name.str;

if (curc->y_sampling > 1)
{
if (cinfo->height == 1)
decc->height = ((cinfo->start_y % curc->y_sampling) == 0) ? 1
: 0;
else
decc->height = cinfo->height / curc->y_sampling;
}
else
decc->height = cinfo->height;
decc->height = compute_sampled_lines (
cinfo->height, curc->y_sampling, cinfo->start_y);

if (curc->x_sampling > 1)
decc->width = cinfo->width / curc->x_sampling;
Expand Down Expand Up @@ -106,16 +99,8 @@ internal_coding_update_channel_info (

ccic->channel_name = curc->name.str;

if (curc->y_sampling > 1)
{
if (cinfo->height == 1)
ccic->height = ((cinfo->start_y % curc->y_sampling) == 0) ? 1
: 0;
else
ccic->height = cinfo->height / curc->y_sampling;
}
else
ccic->height = cinfo->height;
ccic->height = compute_sampled_lines (
cinfo->height, curc->y_sampling, cinfo->start_y);

if (curc->x_sampling > 1)
ccic->width = cinfo->width / curc->x_sampling;
Expand Down
39 changes: 33 additions & 6 deletions src/lib/OpenEXRCore/internal_b44.c
Original file line number Diff line number Diff line change
Expand Up @@ -345,10 +345,7 @@ compress_b44_impl (exr_encode_pipeline_t* encode, int flat_field)
}
tmp += ((uint64_t) (y / curc->y_samples)) * bpl;
}
else
{
tmp += ((uint64_t) y) * bpl;
}
else { tmp += ((uint64_t) y) * bpl; }

memcpy (tmp, packed, bpl);
if (curc->data_type == EXR_PIXEL_HALF) priv_to_native16 (tmp, nx);
Expand Down Expand Up @@ -607,6 +604,36 @@ uncompress_b44_impl (
return EXR_ERR_SUCCESS;
}

/**************************************/

static uint64_t
compute_scratch_buffer_size (
exr_decode_pipeline_t* decode, uint64_t uncompressed_size)
{
const exr_coding_channel_info_t* curc;
int nx, ny;
uint64_t ret = uncompressed_size;
uint64_t comp = 0;

for (int c = 0; c < decode->channel_count; ++c)
{
curc = decode->channels + c;

nx = curc->width;
ny = curc->height;

if (nx % 4) nx += 4 - nx % 4;
if (ny % 4) ny += 4 - ny % 4;

comp += (uint64_t) (ny) * (uint64_t) (nx) *
(uint64_t) (curc->bytes_per_element);
}
if (comp > ret) ret = comp;
return ret;
}

/**************************************/

exr_result_t
internal_exr_undo_b44 (
exr_decode_pipeline_t* decode,
Expand All @@ -621,7 +648,7 @@ internal_exr_undo_b44 (
EXR_TRANSCODE_BUFFER_SCRATCH1,
&(decode->scratch_buffer_1),
&(decode->scratch_alloc_size_1),
uncompressed_size);
compute_scratch_buffer_size (decode, uncompressed_size));
if (rv != EXR_ERR_SUCCESS) return rv;

return uncompress_b44_impl (
Expand All @@ -646,7 +673,7 @@ internal_exr_undo_b44a (
EXR_TRANSCODE_BUFFER_SCRATCH1,
&(decode->scratch_buffer_1),
&(decode->scratch_alloc_size_1),
uncompressed_size);
compute_scratch_buffer_size (decode, uncompressed_size));
if (rv != EXR_ERR_SUCCESS) return rv;

return uncompress_b44_impl (
Expand Down
40 changes: 40 additions & 0 deletions src/lib/OpenEXRCore/internal_util.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
** SPDX-License-Identifier: BSD-3-Clause
** Copyright Contributors to the OpenEXR Project.
*/

#include <stdint.h>

static inline int
compute_sampled_lines (int height, int y_sampling, int start_y)
{
int nlines;

if (y_sampling <= 1) return height;

if (height == 1)
nlines = (start_y % y_sampling) == 0 ? 1 : 0;
else
{
int start, end;

/* computed the number of times y % ysampling == 0, by
* computing interval based on first and last time that occurs
* on the given range
*/
start = start_y % y_sampling;
if (start != 0)
start = start_y + (y_sampling - start);
else
start = start_y;
end = start_y + height - 1;
end -= (end % y_sampling);

if (start > end)
nlines = 0;
else
nlines = (end - start) / y_sampling + 1;
}

return nlines;
}
8 changes: 6 additions & 2 deletions src/lib/OpenEXRCore/internal_zip.c
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ undo_zip_impl (
void* scratch_data,
uint64_t scratch_size)
{
uLong outSize = (uLong) uncompressed_size;
uLong outSize = (uLong) scratch_size;
int rstat;

if (scratch_size < uncompressed_size) return EXR_ERR_INVALID_ARGUMENT;
Expand Down Expand Up @@ -200,12 +200,16 @@ internal_exr_undo_zip (
uint64_t uncompressed_size)
{
exr_result_t rv;
uint64_t scratchbufsz = uncompressed_size;
if ( comp_buf_size > scratchbufsz )
scratchbufsz = comp_buf_size;

rv = internal_decode_alloc_buffer (
decode,
EXR_TRANSCODE_BUFFER_SCRATCH1,
&(decode->scratch_buffer_1),
&(decode->scratch_alloc_size_1),
uncompressed_size);
scratchbufsz);
if (rv != EXR_ERR_SUCCESS) return rv;
return undo_zip_impl (
compressed_data,
Expand Down

0 comments on commit 7629dad

Please sign in to comment.