Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

A possible crash with png_set_quantize and png_read_png #458

Open
hopper-vul opened this issue Dec 29, 2022 · 3 comments
Open

A possible crash with png_set_quantize and png_read_png #458

hopper-vul opened this issue Dec 29, 2022 · 3 comments

Comments

@hopper-vul
Copy link

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];
         }
@hopper-vul
Copy link
Author

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
}

@hopper-vul
Copy link
Author

@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.

@jbowler
Copy link
Contributor

jbowler commented Jun 22, 2023

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.

458.patch

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants