libpng
libpng copied to clipboard
A possible crash with png_set_quantize and png_read_png
Hi,
when fuzzing, we found a crash happend when png_read_png
follows png_set_quantize
.
In png_set_quantize
, it allocs the memory of png_ptr->quantize_index
with the size of parameter num_palette
.
if (full_quantize == 0)
{
int i;
png_ptr->quantize_index = (png_bytep)png_malloc(png_ptr,
(png_alloc_size_t)((png_uint_32)num_palette * (sizeof (png_byte))));
Then, in png_read_png->png_read_image->png_read_row->png_do_read_transformations->png_do_quantize
, if the *sp
is greater than num_palette
, an overflow and a crash will happen.
sp = row;
for (i = 0; i < row_width; i++, sp++)
{
-> *sp = quantize_lookup[*sp];
}
Here is the trigger case, you can compile it to reproduce the crash.
#include "png.h"
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <math.h>
typedef uint8_t u8;
typedef uint16_t u16;
typedef uint32_t u32;
typedef uint64_t u64;
typedef int8_t i8;
typedef int16_t i16;
typedef int32_t i32;
typedef int64_t i64;
typedef float f32;
typedef double f64;
int main() {
i8 v0_tmp[] = {49, 46, 54, 46, 51, 55, 0, }; // user_png_ver
i8 *v0 = malloc(sizeof v0_tmp);
memcpy(v0, v0_tmp, sizeof v0_tmp);
i8 *v1 = v0; // user_png_ver
void *v2 = NULL; // error_ptr
void (*v3)(struct png_struct_def *,i8 *) = NULL; // error_fn
void (*v4)(struct png_struct_def *,i8 *) = NULL; // warn_fn
void *v5 = NULL; // mem_ptr
void * (*v6)(struct png_struct_def *,u64 ) = NULL; // malloc_fn
void (*v7)(struct png_struct_def *,void *) = NULL; // free_fn
struct png_struct_def *v8 = png_create_read_struct_2(v1, v2, v3, v4, v5, v6, v7); // png_ptr
if (v8 == NULL) return 0;
struct png_struct_def *v10 = v8; // png_ptr
u8 v11_tmp[] = {137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82, 0, 0, 0, 32, 0, 0, 0, 32, 8, 3, 0, 0, 0, 68, 164, 138, 198, 0, 0, 0, 25, 116, 69, 88, 116, 83, 111, 102, 116, 119, 97, 114, 101, 0, 65, 100, 111, 98, 101, 32, 73, 109, 97, 103, 101, 82, 101, 97, 100, 121, 113, 201, 101, 60, 0, 0, 0, 15, 80, 76, 84, 69, 102, 204, 204, 255, 255, 255, 0, 0, 0, 51, 153, 102, 153, 255, 204, 62, 76, 175, 21, 0, 0, 0, 97, 73, 68, 65, 84, 120, 218, 220, 147, 49, 14, 192, 32, 12, 3, 147, 152, 255, 191, 185, 52, 20, 9, 212, 58, 97, 97, 160, 55, 176, 248, 36, 11, 11, 68, 19, 68, 213, 2, 110, 193, 10, 71, 204, 5, 161, 224, 167, 130, 111, 23, 8, 207, 186, 84, 168, 33, 48, 26, 111, 1, 240, 147, 86, 180, 60, 16, 122, 77, 32, 76, 249, 183, 48, 228, 68, 72, 150, 68, 34, 76, 67, 238, 169, 56, 246, 201, 213, 155, 81, 108, 229, 243, 38, 92, 2, 12, 0, 210, 102, 3, 53, 176, 215, 203, 154, 0, 0, 0, 0, 73, 69, 78, 68, 174, 66, 96, 130, 0, 0, 73, 69, 78, 68, 174, 66, 96, 130, 0, }; // file_buf
u8 *v11 = malloc(sizeof v11_tmp);
memcpy(v11, v11_tmp, sizeof v11_tmp);
char* v12 = "file___filename_11"; // __filename
FILE *f_v12 = fopen(v12, "wb");
fwrite(v11, sizeof v11_tmp, 1, f_v12);
fclose(f_v12);
i8 v13_tmp[] = {114, 98, 43, 0, }; // __modes
i8 *v13 = malloc(sizeof v13_tmp);
memcpy(v13, v13_tmp, sizeof v13_tmp);
i8 *v14 = v13; // __modes
struct _IO_FILE *v15 = fopen(v12, v14); // fp
if (v15 == NULL) return 0;
struct _IO_FILE *v17 = v15; // fp
png_init_io(v10, v17); // $relative
struct png_info_def *v19 = png_create_info_struct(v10); // info_ptr
if (v19 == NULL) return 0;
struct png_info_def *v21 = v19; // info_ptr
i32 v22 = 4; // transforms
void *v23 = NULL; // params
i32 v24 = 4; // crit_action
i32 v25 = 4; // ancil_action
struct png_color_struct v26_tmp[] = {{ 80, 20, 73, }, }; // palette
struct png_color_struct *v26 = malloc(sizeof v26_tmp);
memcpy(v26, v26_tmp, sizeof v26_tmp);
struct png_color_struct *v27 = v26; // palette
i32 v28 = 1; // num_palette
i32 v29 = -2147483648; // maximum_colors
u16 v30_tmp[] = {55186, 35709, 18046, 53216, 35649, 8202, 39658, 40780, 32750, 31539, 43146, 11343, 62981, 54066, 18192, 53636, 41023, 30038, 35754, 9111, 33548, 24361, 43777, 64919, 4541, 57480, 48919, 35916, 47095, 53551, 50691, 11792, 59671, 59103, 46114, 57464, 31067, 45703, 53662, 12656, 12462, 45052, 3272, 21126, 58373, 2595, 28648, 34720, 356, 53063, 52656, 20073, 64545, 18919, 9369, 1680, 51408, 18390, 28053, 23413, 15458, 44245, 8800, 39724, 0, }; // histogram
u16 *v30 = malloc(sizeof v30_tmp);
memcpy(v30, v30_tmp, sizeof v30_tmp);
u16 *v31 = v30; // histogram
i32 v32 = 0; // full_quantize
png_set_quantize(v10, v27, v28, v29, v31, v32); // $relative
png_read_png(v10, v21, v22, v23); // $relative
}
@thealberto hi, we have found some fresh crashes. That seems the png_read_png
function has some problems actually and maybe suffer security risks. Hope those problems could be properly fixed.
Best regards.
To quote the manual for png_read_png:
"You must use png_transforms[the parameter to png_read_png] and not call any png_set_transform() functions when you use png_read_png."
Here's a patch that detects the error. It uses png_app_error but if that is ignored it just zeros out the transformations.