[libpng17] Revised overflow detection in pngwutil.c

This commit is contained in:
Glenn Randers-Pehrson 2015-02-16 22:43:52 -06:00
parent d368235da4
commit 1d3a1e36a7

View File

@ -1974,7 +1974,8 @@ png_write_alloc_filter_row_buffers(png_structrp png_ptr, int filters)
num_filters++;
if (num_filters > 1)
png_ptr->tst_row = png_voidcast(png_bytep, png_malloc(png_ptr, buf_size));
png_ptr->tst_row = png_voidcast(png_bytep,
png_malloc(png_ptr, buf_size));
}
}
#endif /* WRITE_FILTER */
@ -2372,17 +2373,9 @@ png_setup_sub_row(png_structrp png_ptr, const png_uint_32 bpp,
for (lp = png_ptr->row_buf + 1; i < row_bytes;
i++, rp++, lp++, dp++)
{
png_size_t old_sum = sum;
v = *dp = (png_byte)(((int)*rp - (int)*lp) & 0xff);
sum += (v < 128) ? v : 256 - v;
if (sum < old_sum) /* overflow happened */
{
sum = PNG_SIZE_MAX - 1;
break;
}
if (sum > lmins) /* We are already worse, don't continue. */
break;
}
@ -2405,17 +2398,9 @@ png_setup_up_row(png_structrp png_ptr, const png_size_t row_bytes,
pp = png_ptr->prev_row + 1; i < row_bytes;
i++, rp++, pp++, dp++)
{
png_size_t old_sum = sum;
v = *dp = (png_byte)(((int)*rp - (int)*pp) & 0xff);
sum += (v < 128) ? v : 256 - v;
if (sum < old_sum) /* overflow happened */
{
sum = PNG_SIZE_MAX - 1;
break;
}
if (sum > lmins) /* We are already worse, don't continue. */
break;
}
@ -2444,19 +2429,11 @@ png_setup_avg_row(png_structrp png_ptr, const png_uint_32 bpp,
for (lp = png_ptr->row_buf + 1; i < row_bytes; i++)
{
png_size_t old_sum = sum;
v = *dp++ = (png_byte)(((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2))
& 0xff);
sum += (v < 128) ? v : 256 - v;
if (sum < old_sum) /* overflow happened */
{
sum = PNG_SIZE_MAX - 1;
break;
}
if (sum > lmins) /* We are already worse, don't continue. */
break;
}
@ -2487,7 +2464,6 @@ png_setup_paeth_row(png_structrp png_ptr, const png_uint_32 bpp,
i++)
{
int a, b, c, pa, pb, pc, p;
png_size_t old_sum = sum;
b = *pp++;
c = *cp++;
@ -2512,12 +2488,6 @@ png_setup_paeth_row(png_structrp png_ptr, const png_uint_32 bpp,
sum += (v < 128) ? v : 256 - v;
if (sum < old_sum) /* overflow happened */
{
sum = PNG_SIZE_MAX - 1;
break;
}
if (sum > lmins) /* We are already worse, don't continue. */
break;
}
@ -2525,12 +2495,54 @@ png_setup_paeth_row(png_structrp png_ptr, const png_uint_32 bpp,
return (sum);
}
#define PNG_MAXSUM (((png_uint_32)(-1)) >> 1)
#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
#define PNG_MAXSUM (((png_uint_32)(-1)) >> 1)
#define PNG_HISHIFT 10
#define PNG_LOMASK ((png_uint_32)0xffffL)
#define PNG_HIMASK ((png_uint_32)(~PNG_LOMASK >> PNG_HISHIFT))
static png_size_t /* PRIVATE */
png_increase_lmins(png_structrp png_ptr, png_size_t lmins)
{
/* We temporarily increase the "minimum sum" by the factor we
* would reduce the sum of this filter, so that we can do the
* early exit comparison without scaling the sum each time.
*/
int j;
png_uint_32 lmhi, lmlo;
lmlo = lmins & PNG_LOMASK;
lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;
for (j = 0; j < png_ptr->num_prev_filters; j++)
{
if (png_ptr->prev_filters[j] == png_ptr->try_row[0])
{
lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >>
PNG_WEIGHT_SHIFT;
lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >>
PNG_WEIGHT_SHIFT;
}
}
lmlo = (lmlo * png_ptr->inv_filter_costs[png_ptr->try_row[0]]) >>
PNG_COST_SHIFT;
lmhi = (lmhi * png_ptr->inv_filter_costs[png_ptr->try_row[0]]) >>
PNG_COST_SHIFT;
if (lmhi > PNG_HIMASK)
lmins = PNG_MAXSUM;
else
lmins = (lmhi << PNG_HISHIFT) + lmlo;
return (lmins);
}
#endif /* WRITE_WEIGHTED_FILTER */
#endif /* WRITE_FILTER */
void /* PRIVATE */
@ -2563,7 +2575,8 @@ png_write_find_filter(png_structrp png_ptr, png_row_infop row_info)
bpp = (row_info->pixel_depth + 7) >> 3;
row_buf = png_ptr->row_buf;
mins = PNG_SIZE_MAX;
mins = PNG_SIZE_MAX - 256/* so we can detect potential overflow of the
running sum */;
/* The prediction method we use is to find which method provides the
* smallest value when summing the absolute values of the distances
@ -2595,6 +2608,7 @@ png_write_find_filter(png_structrp png_ptr, png_row_infop row_info)
*/
best_row = png_ptr->row_buf;
if ((filter_to_do & PNG_FILTER_NONE) != 0 && filter_to_do != PNG_FILTER_NONE)
{
png_bytep rp;
@ -2602,12 +2616,6 @@ png_write_find_filter(png_structrp png_ptr, png_row_infop row_info)
png_size_t i;
int v;
for (i = 0, rp = row_buf + 1; i < row_bytes; i++, rp++)
{
v = *rp;
sum += (v < 128) ? v : 256 - v;
}
#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
{
@ -2646,6 +2654,28 @@ png_write_find_filter(png_structrp png_ptr, png_row_infop row_info)
sum = (sumhi << PNG_HISHIFT) + sumlo;
}
#endif
if (PNG_SIZE_MAX/128 <= row_bytes)
{
for (i = 0, rp = row_buf + 1; i < row_bytes; i++, rp++)
{
/* Check for overflow */
if (sum > PNG_SIZE_MAX/128 - 256)
break;
v = *rp;
sum += (v < 128) ? v : 256 - v;
}
}
else /* Overflow is not possible */
{
for (i = 0, rp = row_buf + 1; i < row_bytes; i++, rp++)
{
v = *rp;
sum += (v < 128) ? v : 256 - v;
}
}
mins = sum;
}
@ -2661,43 +2691,10 @@ png_write_find_filter(png_structrp png_ptr, png_row_infop row_info)
{
png_size_t sum;
png_size_t lmins = mins;
#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
/* We temporarily increase the "minimum sum" by the factor we
* would reduce the sum of this filter, so that we can do the
* early exit comparison without scaling the sum each time.
*/
png_ptr->try_row[0] = PNG_FILTER_VALUE_SUB;
if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
{
int j;
png_uint_32 lmhi, lmlo;
lmlo = lmins & PNG_LOMASK;
lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;
for (j = 0; j < num_p_filters; j++)
{
if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_SUB)
{
lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >>
PNG_WEIGHT_SHIFT;
lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >>
PNG_WEIGHT_SHIFT;
}
}
lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >>
PNG_COST_SHIFT;
lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >>
PNG_COST_SHIFT;
if (lmhi > PNG_HIMASK)
lmins = PNG_MAXSUM;
else
lmins = (lmhi << PNG_HISHIFT) + lmlo;
}
lmins = png_increase_lmins(png_ptr, lmins);
#endif
sum = png_setup_sub_row(png_ptr, bpp, row_bytes, lmins);
@ -2759,39 +2756,10 @@ png_write_find_filter(png_structrp png_ptr, png_row_infop row_info)
{
png_size_t sum;
png_size_t lmins = mins;
#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
png_ptr->try_row[0] = PNG_FILTER_VALUE_UP;
if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
{
int j;
png_uint_32 lmhi, lmlo;
lmlo = lmins & PNG_LOMASK;
lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;
for (j = 0; j < num_p_filters; j++)
{
if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_UP)
{
lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >>
PNG_WEIGHT_SHIFT;
lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >>
PNG_WEIGHT_SHIFT;
}
}
lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_UP]) >>
PNG_COST_SHIFT;
lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_UP]) >>
PNG_COST_SHIFT;
if (lmhi > PNG_HIMASK)
lmins = PNG_MAXSUM;
else
lmins = (lmhi << PNG_HISHIFT) + lmlo;
}
lmins = png_increase_lmins(png_ptr, lmins);
#endif
sum = png_setup_up_row(png_ptr, row_bytes, lmins);
@ -2853,39 +2821,10 @@ png_write_find_filter(png_structrp png_ptr, png_row_infop row_info)
{
png_size_t sum;
png_size_t lmins = mins;
#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
png_ptr->try_row[0] = PNG_FILTER_VALUE_AVG;
if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
{
int j;
png_uint_32 lmhi, lmlo;
lmlo = lmins & PNG_LOMASK;
lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;
for (j = 0; j < num_p_filters; j++)
{
if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_AVG)
{
lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >>
PNG_WEIGHT_SHIFT;
lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >>
PNG_WEIGHT_SHIFT;
}
}
lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_AVG]) >>
PNG_COST_SHIFT;
lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_AVG]) >>
PNG_COST_SHIFT;
if (lmhi > PNG_HIMASK)
lmins = PNG_MAXSUM;
else
lmins = (lmhi << PNG_HISHIFT) + lmlo;
}
lmins = png_increase_lmins(png_ptr, lmins);
#endif
sum= png_setup_avg_row(png_ptr, bpp, row_bytes, lmins);
@ -2947,39 +2886,10 @@ png_write_find_filter(png_structrp png_ptr, png_row_infop row_info)
{
png_size_t sum;
png_size_t lmins = mins;
#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
png_ptr->try_row[0] = PNG_FILTER_VALUE_PAETH;
if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
{
int j;
png_uint_32 lmhi, lmlo;
lmlo = lmins & PNG_LOMASK;
lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;
for (j = 0; j < num_p_filters; j++)
{
if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_PAETH)
{
lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >>
PNG_WEIGHT_SHIFT;
lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >>
PNG_WEIGHT_SHIFT;
}
}
lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_PAETH]) >>
PNG_COST_SHIFT;
lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_PAETH]) >>
PNG_COST_SHIFT;
if (lmhi > PNG_HIMASK)
lmins = PNG_MAXSUM;
else
lmins = (lmhi << PNG_HISHIFT) + lmlo;
}
lmins = png_increase_lmins(png_ptr, lmins);
#endif
sum = png_setup_paeth_row(png_ptr, bpp, row_bytes, lmins);