Skip to content

Commit

Permalink
Cleanup and better safety checks, 8
Browse files Browse the repository at this point in the history
  • Loading branch information
aaaaaa123456789 committed Jan 23, 2022
1 parent 492c785 commit 0264c24
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 56 deletions.
26 changes: 16 additions & 10 deletions src/pngcompress.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ unsigned char * compress_PNG_data (struct context * context, const unsigned char
unsigned char * output = ctxmalloc(context, extra + 8); // two bytes extra to handle leftover bits in dataword
memset(output, 0, extra);
size_t p, inoffset = 0, outoffset = extra + byteappend(output + extra, 0x78, 0x5e);
uint16_t * references = ctxmalloc(context, 0x8000u * PNG_MAX_LOOKBACK_COUNT * sizeof *references);
for (p = 0; p < (0x8000u * PNG_MAX_LOOKBACK_COUNT); p ++) references[p] = 0xffffu;
uint16_t * references = ctxmalloc(context, sizeof *references * 0x8000u * PNG_MAX_LOOKBACK_COUNT);
for (p = 0; p < ((size_t) 0x8000u * PNG_MAX_LOOKBACK_COUNT); p ++) references[p] = 0xffffu;
uint32_t dataword = 0;
uint8_t bits = 0;
int force = 0;
Expand All @@ -21,6 +21,7 @@ unsigned char * compress_PNG_data (struct context * context, const unsigned char
if (inoffset == size) dataword |= 1 << bits;
bits ++;
unsigned char * compressed_data = emit_PNG_compressed_block(context, compressed, count, count >= 16, &blocksize, &dataword, &bits);
if ((SIZE_MAX - outoffset) < (blocksize + 6)) throw(context, PLUM_ERR_IMAGE_TOO_LARGE);
output = ctxrealloc(context, output, outoffset + blocksize + 6);
memcpy(output + outoffset, compressed_data, blocksize);
ctxfree(context, compressed_data);
Expand All @@ -37,6 +38,7 @@ unsigned char * compress_PNG_data (struct context * context, const unsigned char
dataword >>= 8;
bits = (bits >= 8) ? bits - 8 : 0;
}
if ((SIZE_MAX - outoffset) < (blocksize + 10)) throw(context, PLUM_ERR_IMAGE_TOO_LARGE);
output = ctxrealloc(context, output, outoffset + blocksize + 10);
write_le16_unaligned(output + outoffset, blocksize);
write_le16_unaligned(output + outoffset + 2, 0xffffu - blocksize);
Expand Down Expand Up @@ -168,14 +170,12 @@ void emit_PNG_code (struct context * context, struct compressed_PNG_code ** code
code = -code;
// one extra entry to make looking codes up easier
static const uint_fast16_t lengths[] = {3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 259};
static const uint_fast16_t distances[] = {1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097,
6145, 8193, 12289, 16385, 24577, 32769};
unsigned p;
for (p = 0; lengths[p] <= code; p ++);
result.datacode = 256 + p;
result.dataextra = code - lengths[p - 1];
for (p = 0; distances[p] <= ref; p ++);
result.distcode = p - 1;
static const uint_fast16_t distances[] = {1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
8193, 12289, 16385, 24577, 32769};
for (result.datacode = 0; lengths[result.datacode + 1] <= code; result.datacode ++);
result.dataextra = code - lengths[result.datacode];
result.datacode += 0x101;
for (result.distcode = 0; distances[result.distcode + 1] <= ref; result.distcode ++);
result.distextra = ref - distances[result.distcode];
}
(*codes)[(*count) ++] = result;
Expand Down Expand Up @@ -221,11 +221,17 @@ unsigned char * emit_PNG_compressed_block (struct context * context, const struc
for (p = 0; p < 0x11e; p ++) {
uint_fast8_t valuesize = codelengths[p];
if ((p >= 0x109) && (p < 0x11d)) valuesize += (p - 0x105) >> 2;
if (!valuesize) continue;
if (((codecounts[p] * valuesize / valuesize) != codecounts[p]) || ((SIZE_MAX - outsize) < (codecounts[p] * valuesize)))
throw(context, PLUM_ERR_IMAGE_TOO_LARGE);
outsize += codecounts[p] * valuesize;
}
for (p = 0; p < 30; p ++) {
uint_fast8_t valuesize = distlengths[p];
if (p >= 4) valuesize += (p - 2) >> 1;
if (!valuesize) continue;
if (((distcounts[p] * valuesize / valuesize) != distcounts[p]) || ((SIZE_MAX - outsize) < (distcounts[p] * valuesize)))
throw(context, PLUM_ERR_IMAGE_TOO_LARGE);
outsize += distcounts[p] * valuesize;
}
outsize >>= 3;
Expand Down
23 changes: 9 additions & 14 deletions src/pngdecompress.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ void * decompress_PNG_data (struct context * context, const unsigned char * comp
size -= 6; // pretend the checksum is not part of the data
unsigned char * decompressed = ctxmalloc(context, expected);
size_t current = 0;
int more_blocks;
int last_block;
uint32_t dataword = 0;
uint8_t bits = 0;
do {
more_blocks = !shift_in_left(context, 1, &dataword, &bits, &compressed, &size);
last_block = shift_in_left(context, 1, &dataword, &bits, &compressed, &size);
switch (shift_in_left(context, 2, &dataword, &bits, &compressed, &size)) {
case 0: {
dataword >>= bits & 7;
Expand Down Expand Up @@ -50,7 +50,7 @@ void * decompress_PNG_data (struct context * context, const unsigned char * comp
default:
throw(context, PLUM_ERR_INVALID_FILE_FORMAT);
}
} while (more_blocks);
} while (!last_block);
if (size || (current != expected)) throw(context, PLUM_ERR_INVALID_FILE_FORMAT);
if (compute_Adler32_checksum(decompressed, expected) != read_be32_unaligned(compressed)) throw(context, PLUM_ERR_INVALID_FILE_FORMAT);
return decompressed;
Expand Down Expand Up @@ -79,13 +79,8 @@ void extract_PNG_code_table (struct context * context, const unsigned char ** co
code = codesizes[p - 1];
while (count --) codesizes[p ++] = code;
break;
case 17:
count = 3 + shift_in_left(context, 3, dataword, bits, compressed, size);
if ((p + count) > (literals + distances)) throw(context, PLUM_ERR_INVALID_FILE_FORMAT);
while (count --) codesizes[p ++] = 0;
break;
case 18:
count = 11 + shift_in_left(context, 7, dataword, bits, compressed, size);
case 17: case 18:
count = ((code == 18) ? 11 : 3) + shift_in_left(context, (code == 18) ? 7 : 3, dataword, bits, compressed, size);
if ((p + count) > (literals + distances)) throw(context, PLUM_ERR_INVALID_FILE_FORMAT);
while (count --) codesizes[p ++] = 0;
break;
Expand Down Expand Up @@ -117,14 +112,14 @@ void decompress_PNG_block (struct context * context, const unsigned char ** comp
}
if (!disttree) throw(context, PLUM_ERR_INVALID_FILE_FORMAT);
code -= 0x101;
uint_fast16_t length = code[(const uint_fast16_t []) {3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67,
83, 99, 115, 131, 163, 195, 227, 258}];
uint_fast16_t length = code[(const uint_fast16_t []) {3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195,
227, 258}];
code = code[(const uint_fast16_t []) {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0}];
if (code) length += shift_in_left(context, code, dataword, bits, compressed, size);
code = next_PNG_Huffman_code(context, disttree, compressed, size, dataword, bits);
if (code > 29) throw(context, PLUM_ERR_INVALID_FILE_FORMAT);
uint_fast16_t distance = code[(const uint_fast16_t []) {1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537,
2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577}];
uint_fast16_t distance = code[(const uint_fast16_t []) {1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073,
4097, 6145, 8193, 12289, 16385, 24577}];
code = code[(const uint_fast16_t []) {0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13}];
if (code) distance += shift_in_left(context, code, dataword, bits, compressed, size);
if (distance > *current) throw(context, PLUM_ERR_INVALID_FILE_FORMAT);
Expand Down
56 changes: 24 additions & 32 deletions src/pngread.c
Original file line number Diff line number Diff line change
Expand Up @@ -167,22 +167,25 @@ struct PNG_chunk_locations * load_PNG_chunk_locations (struct context * context)
result -> transparency = offset;
break;
case 0x6163544cu: // acTL
if (result -> data || result -> animation || (length != 8))
invalid_animation = 1;
else
result -> animation = offset;
if (!invalid_animation)
if (result -> data || result -> animation || (length != 8))
invalid_animation = 1;
else
result -> animation = offset;
break;
case 0x6663544cu: // fcTL
if (length == 26)
append_PNG_chunk_location(context, &result -> frameinfo, offset, &frameinfo_count);
else
invalid_animation = 1;
if (!invalid_animation)
if (length == 26)
append_PNG_chunk_location(context, &result -> frameinfo, offset, &frameinfo_count);
else
invalid_animation = 1;
break;
case 0x66644154u: // fdAT
if (length >= 4)
append_PNG_chunk_location(context, &framedata, offset, &framedata_count);
else
invalid_animation = 1;
if (!invalid_animation)
if (length >= 4)
append_PNG_chunk_location(context, &framedata, offset, &framedata_count);
else
invalid_animation = 1;
break;
default:
if ((chunk_type & 0xe0c0c0c0u) != 0x60404040u) throw(context, PLUM_ERR_INVALID_FILE_FORMAT); // invalid or critical
Expand All @@ -203,8 +206,7 @@ struct PNG_chunk_locations * load_PNG_chunk_locations (struct context * context)
ctxfree(context, result -> frameinfo);
result -> animation = 0;
result -> frameinfo = NULL;
}
if (result -> animation) {
} else if (result -> animation) {
// validate and initialize frame counts here to avoid having to count them up later
if (frameinfo_count != read_be32_unaligned(context -> data + result -> animation)) throw(context, PLUM_ERR_INVALID_FILE_FORMAT);
sort_PNG_animation_chunks(context, result, framedata, frameinfo_count, framedata_count);
Expand Down Expand Up @@ -259,13 +261,7 @@ uint8_t load_PNG_palette (struct context * context, const struct PNG_chunk_locat
size_t p, count = read_be32_unaligned(context -> data + chunks -> palette - 8) / 3;
if (count > (1 << bitdepth)) throw(context, PLUM_ERR_INVALID_FILE_FORMAT);
const unsigned char * data = context -> data + chunks -> palette;
uint64_t color;
for (p = 0; p < count; p ++) {
color = *(data ++);
color |= (uint64_t) *(data ++) << 16;
color |= (uint64_t) *(data ++) << 32;
palette[p] = color * 0x101;
}
for (p = 0; p < count; p ++) palette[p] = (data[p * 3] | ((uint64_t) data[p * 3 + 1] << 16) | ((uint64_t) data[p * 3 + 2] << 32)) * 0x101;
if (chunks -> transparency) {
unsigned transparency_count = read_be32_unaligned(context -> data + chunks -> transparency - 8);
if (transparency_count > count) throw(context, PLUM_ERR_INVALID_FILE_FORMAT);
Expand Down Expand Up @@ -367,11 +363,8 @@ uint64_t add_PNG_background_metadata (struct context * context, const struct PNG
if (bitdepth == 8) {
if (*data || data[2] || data[4]) throw(context, PLUM_ERR_INVALID_FILE_FORMAT);
color = ((uint64_t) data[1] | ((uint64_t) data[3] << 16) | ((uint64_t) data[5] << 32)) * 0x101;
} else {
color = read_be16_unaligned(data);
color |= (uint64_t) read_be16_unaligned(data + 2) << 16;
color |= (uint64_t) read_be16_unaligned(data + 4) << 32;
}
} else
color = read_be16_unaligned(data) | ((uint64_t) read_be16_unaligned(data + 2) << 16) | ((uint64_t) read_be16_unaligned(data + 4) << 32);
}
add_background_color_metadata(context, color, flags);
return color;
Expand All @@ -382,15 +375,14 @@ uint64_t load_PNG_transparent_color (struct context * context, size_t offset, ui
const unsigned char * data = context -> data + offset;
if (read_be32_unaligned(data - 8) != (imagetype ? 6 : 2)) throw(context, PLUM_ERR_INVALID_FILE_FORMAT);
if (!imagetype) {
uint64_t color = read_be16_unaligned(data); // cannot be uint16_t because of the potential >> 16 in the next line
uint_fast32_t color = read_be16_unaligned(data); // cannot be 16-bit because of the potential >> 16 in the next line
if (color >> bitdepth) throw(context, PLUM_ERR_INVALID_FILE_FORMAT);
return 0x100010001u * (uint64_t) bitextend(color, bitdepth);
}
if (bitdepth == 16)
} else if (bitdepth == 8) {
if (*data || data[2] || data[4]) throw(context, PLUM_ERR_INVALID_FILE_FORMAT);
return ((uint64_t) data[1] | ((uint64_t) data[3] << 16) | ((uint64_t) data[5] << 32)) * 0x101;
} else
return (uint64_t) read_be16_unaligned(data) | ((uint64_t) read_be16_unaligned(data + 2) << 16) | ((uint64_t) read_be16_unaligned(data + 4) << 32);
if (*data || data[2] || data[4]) throw(context, PLUM_ERR_INVALID_FILE_FORMAT);
uint64_t color = (uint64_t) data[1] | ((uint64_t) data[3] << 16) | ((uint64_t) data[5] << 32);
return color * 0x101;
}

int check_PNG_reduced_frames (struct context * context, const struct PNG_chunk_locations * chunks) {
Expand Down

0 comments on commit 0264c24

Please sign in to comment.