Repository: ittiam-systems/libavc
Fuzzing engine: libfuzzer
Fuzz target: svc_dec_fuzzer
Sanitizer: address
Crash type: Heap-buffer-overflow WRITE 1

Sanitizer report:
INFO: Running with entropic power schedule (0xFF, 100).
INFO: Seed: 24585150
INFO: Loaded 1 modules   (16740 inline 8-bit counters): 16740 [0x5630a2f9d5f0, 0x5630a2fa1754), 
INFO: Loaded 1 PC tables (16740 PCs): 16740 [0x5630a2fa1758,0x5630a2fe2d98), 
/out/svc_dec_fuzzer: Running 1 inputs 1 time(s) each.
Running: /testcase/OSV-2023-1205.poc
=================================================================
==7==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x524000007eb4 at pc 0x5630a2d7a420 bp 0x7fff87db0530 sp 0x7fff87db0528
WRITE of size 1 at 0x524000007eb4 thread T0
SCARINESS: 31 (1-byte-write-heap-buffer-overflow)
    #0 0x5630a2d7a41f in isvcd_populate_res_prms /src/libavc/decoder/svc/isvcd_intra_resamp.c:4802:37
    #1 0x5630a2d34c83 in isvcd_parse_interlayer_resamp_func_init /src/libavc/decoder/svc/isvcd_parse_epslice.c:3198:15
    #2 0x5630a2d4cdfb in isvcd_parse_decode_slice /src/libavc/decoder/svc/isvcd_parse_slice.c:2453:15
    #3 0x5630a2d3a933 in isvcd_parse_nal_unit /src/libavc/decoder/svc/isvcd_parse_headers.c:1016:40
    #4 0x5630a2d058bc in isvcd_video_decode /src/libavc/decoder/svc/isvcd_api.c:5291:27
    #5 0x5630a2cf2646 in Codec::decodeFrame(unsigned char const*, unsigned long, unsigned long*) /src/libavc/fuzzer/svc_dec_fuzzer.cpp:375:11
    #6 0x5630a2cf319e in LLVMFuzzerTestOneInput /src/libavc/fuzzer/svc_dec_fuzzer.cpp:437:22
    #7 0x5630a2ba5300 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:614:13
    #8 0x5630a2b90575 in fuzzer::RunOneTest(fuzzer::Fuzzer*, char const*, unsigned long) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerDriver.cpp:327:6
    #9 0x5630a2b9600f in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerDriver.cpp:862:9
    #10 0x5630a2bc12b2 in main /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerMain.cpp:20:10
    #11 0x7f2eab856082 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x24082) (BuildId: 0702430aef5fa3dda43986563e9ffcc47efbd75e)
    #12 0x5630a2b8875d in _start (/out/svc_dec_fuzzer+0xa375d)

DEDUP_TOKEN: isvcd_populate_res_prms--isvcd_parse_interlayer_resamp_func_init--isvcd_parse_decode_slice
0x524000007eb4 is located 4 bytes after 7600-byte region [0x524000006100,0x524000007eb0)
allocated by thread T0 here:
    #0 0x5630a2cb1b77 in posix_memalign /src/llvm-project/compiler-rt/lib/asan/asan_malloc_linux.cpp:142:3
    #1 0x5630a2cf0856 in iv_aligned_malloc(void*, int, int) /src/libavc/fuzzer/svc_dec_fuzzer.cpp:85:13
    #2 0x5630a2d653b5 in isvcd_allocate_dynamic_bufs /src/libavc/decoder/svc/isvcd_utils.c:178:14
    #3 0x5630a2d68798 in isvcd_init_pic /src/libavc/decoder/svc/isvcd_utils.c:843:15
    #4 0x5630a2d3f653 in isvcd_start_of_pic /src/libavc/decoder/svc/isvcd_parse_slice.c:283:11
    #5 0x5630a2d4cd6b in isvcd_parse_decode_slice /src/libavc/decoder/svc/isvcd_parse_slice.c:2429:19
    #6 0x5630a2d3a933 in isvcd_parse_nal_unit /src/libavc/decoder/svc/isvcd_parse_headers.c:1016:40
    #7 0x5630a2d058bc in isvcd_video_decode /src/libavc/decoder/svc/isvcd_api.c:5291:27
    #8 0x5630a2cf2646 in Codec::decodeFrame(unsigned char const*, unsigned long, unsigned long*) /src/libavc/fuzzer/svc_dec_fuzzer.cpp:375:11
    #9 0x5630a2cf319e in LLVMFuzzerTestOneInput /src/libavc/fuzzer/svc_dec_fuzzer.cpp:437:22
    #10 0x5630a2ba5300 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:614:13
    #11 0x5630a2b90575 in fuzzer::RunOneTest(fuzzer::Fuzzer*, char const*, unsigned long) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerDriver.cpp:327:6
    #12 0x5630a2b9600f in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerDriver.cpp:862:9
    #13 0x5630a2bc12b2 in main /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerMain.cpp:20:10
    #14 0x7f2eab856082 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x24082) (BuildId: 0702430aef5fa3dda43986563e9ffcc47efbd75e)

DEDUP_TOKEN: ___interceptor_posix_memalign--iv_aligned_malloc(void*, int, int)--isvcd_allocate_dynamic_bufs
SUMMARY: AddressSanitizer: heap-buffer-overflow /src/libavc/decoder/svc/isvcd_intra_resamp.c:4802:37 in isvcd_populate_res_prms
Shadow bytes around the buggy address:
  0x524000007c00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x524000007c80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x524000007d00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x524000007d80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x524000007e00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x524000007e80: 00 00 00 00 00 00[fa]fa fa fa fa fa fa fa fa fa
  0x524000007f00: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x524000007f80: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x524000008000: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x524000008080: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x524000008100: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
==7==ABORTING


Fix patch:
diff --git a/decoder/svc/isvcd_api.c b/decoder/svc/isvcd_api.c
index 38d876d..c789785 100644
--- a/decoder/svc/isvcd_api.c
+++ b/decoder/svc/isvcd_api.c
@@ -4435,6 +4435,15 @@ WORD32 isvcd_dec_non_vcl(void *pv_out_non_vcl, void *pv_seq_params, void *pv_pic
                 {
                     ps_dec->i4_header_decoded |= 0x1;
                     ps_svcd_ctxt->u4_num_sps_ctr++;
+
+                    if(ps_svcd_ctxt->pic_width < ps_svc_lyr_dec->pic_width)
+                    {
+                        ps_svcd_ctxt->pic_width = ps_svc_lyr_dec->pic_width;
+                    }
+                    if(ps_svcd_ctxt->pic_height < ps_svc_lyr_dec->pic_height)
+                    {
+                        ps_svcd_ctxt->pic_height = ps_svc_lyr_dec->pic_height;
+                    }
                 }
 
                 if(i_status) return i_status;
@@ -4448,6 +4457,15 @@ WORD32 isvcd_dec_non_vcl(void *pv_out_non_vcl, void *pv_seq_params, void *pv_pic
                 {
                     ps_svcd_ctxt->u4_num_sps_ctr++;
                     ps_dec->i4_header_decoded |= 0x1;
+
+                    if(ps_svcd_ctxt->pic_width < ps_svc_lyr_dec->pic_width)
+                    {
+                        ps_svcd_ctxt->pic_width = ps_svc_lyr_dec->pic_width;
+                    }
+                    if(ps_svcd_ctxt->pic_height < ps_svc_lyr_dec->pic_height)
+                    {
+                        ps_svcd_ctxt->pic_height = ps_svc_lyr_dec->pic_height;
+                    }
                 }
                 if(i_status) return i_status;
 
@@ -6086,16 +6104,8 @@ WORD32 isvcd_get_buf_info(iv_obj_t *dec_hdl, void *pv_api_ip, void *pv_api_op)
 
     if(ps_dec->i4_header_decoded == 3)
     {
-        if(0 == ps_dec->u4_share_disp_buf)
-        {
-            pic_wd = ps_dec->u2_disp_width;
-            pic_ht = ps_dec->u2_disp_height;
-        }
-        else
-        {
-            pic_wd = ps_dec->u2_frm_wd_y;
-            pic_ht = ps_dec->u2_frm_ht_y;
-        }
+        pic_wd = ps_svcd_ctxt->pic_width;
+        pic_ht = ps_svcd_ctxt->pic_height;
     }
 
     for(i = 0; i < ps_ctl_op->u4_min_num_in_bufs; i++)
diff --git a/decoder/svc/isvcd_parse_headers.c b/decoder/svc/isvcd_parse_headers.c
index abf4a1b..d137040 100644
--- a/decoder/svc/isvcd_parse_headers.c
+++ b/decoder/svc/isvcd_parse_headers.c
@@ -193,14 +193,6 @@ WORD32 isvcd_parse_subset_sps(svc_dec_lyr_struct_t *ps_svc_lyr_dec, dec_bit_stre
     ps_seq = ps_dec->pv_scratch_sps_pps;
     memset(ps_seq, 0, sizeof(dec_seq_params_t));
 
-    if(ps_dec->i4_header_decoded & 1)
-    {
-        if(NULL != ps_dec->ps_cur_sps)
-            *ps_seq = *ps_dec->ps_cur_sps;
-        else
-            return ERROR_INV_SPS_PPS_T;
-    }
-
     ps_seq->u1_profile_idc = u1_profile_idc;
     ps_seq->u1_level_idc = u1_level_idc;
     ps_seq->u1_seq_parameter_set_id = u1_seq_parameter_set_id;
@@ -414,6 +406,15 @@ WORD32 isvcd_parse_subset_sps(svc_dec_lyr_struct_t *ps_svc_lyr_dec, dec_bit_stre
 
     u2_pic_wd = (u4_pic_width_in_mbs << 4);
     u2_pic_ht = (u4_pic_height_in_map_units << 4);
+    if(ps_svc_lyr_dec->pic_width < u2_pic_wd)
+    {
+        ps_svc_lyr_dec->pic_width = u2_pic_wd;
+    }
+    if(ps_svc_lyr_dec->pic_height < u2_pic_ht)
+    {
+        ps_svc_lyr_dec->pic_height = u2_pic_ht;
+    }
+
     /*--------------------------------------------------------------------*/
     /* Get the value of MaxMbAddress and Number of bits needed for it     */
     /*--------------------------------------------------------------------*/
@@ -850,35 +851,6 @@ WORD32 isvcd_parse_subset_sps(svc_dec_lyr_struct_t *ps_svc_lyr_dec, dec_bit_stre
     ps_subset_seq->u2_crop_offset_y = u2_crop_offset_y;
     ps_subset_seq->u2_crop_offset_uv = u2_crop_offset_uv;
 
-    if(((ps_dec->u2_pic_wd * ps_dec->u2_pic_ht) <
-        (ps_subset_seq->u2_pic_wd * ps_subset_seq->u2_pic_ht)) ||
-       (ps_dec->i4_reorder_depth < ps_subset_seq->i4_reorder_depth))
-    {
-        ps_dec->i4_reorder_depth = ps_subset_seq->i4_reorder_depth;
-
-        ps_dec->u2_disp_height = ps_subset_seq->u2_disp_height;
-        ps_dec->u2_disp_width = ps_subset_seq->u2_disp_width;
-
-        ps_dec->u2_pic_wd = ps_subset_seq->u2_pic_wd;
-        ps_dec->u2_pic_ht = ps_subset_seq->u2_pic_ht;
-        ps_dec->u4_total_mbs = ps_seq->u2_total_num_of_mbs << (1 - ps_seq->u1_frame_mbs_only_flag);
-
-        /* Determining the Width and Height of Frame from that of Picture */
-        ps_dec->u2_frm_wd_y = ps_subset_seq->u2_frm_wd_y;
-        ps_dec->u2_frm_ht_y = ps_subset_seq->u2_frm_ht_y;
-        ps_dec->u2_frm_wd_uv = ps_subset_seq->u2_frm_wd_uv;
-        ps_dec->u2_frm_ht_uv = ps_subset_seq->u2_frm_ht_uv;
-
-        ps_dec->s_pad_mgr.u1_pad_len_y_v = ps_subset_seq->u1_pad_len_y_v;
-        ps_dec->s_pad_mgr.u1_pad_len_cr_v = ps_subset_seq->u1_pad_len_cr_v;
-
-        ps_dec->u2_frm_wd_in_mbs = ps_seq->u2_frm_wd_in_mbs;
-        ps_dec->u2_frm_ht_in_mbs = ps_seq->u2_frm_ht_in_mbs;
-
-        ps_dec->u2_crop_offset_y = ps_subset_seq->u2_crop_offset_y;
-        ps_dec->u2_crop_offset_uv = ps_subset_seq->u2_crop_offset_uv;
-    }
-
     ps_seq->u1_is_valid = TRUE;
     ps_dec->ps_sps[u1_seq_parameter_set_id] = *ps_seq;
     if(NULL != ps_svc_lyr_dec->ps_subset_sps[u1_seq_parameter_set_id].s_sps_svc_ext.ps_svc_vui_ext)
@@ -887,7 +859,6 @@ WORD32 isvcd_parse_subset_sps(svc_dec_lyr_struct_t *ps_svc_lyr_dec, dec_bit_stre
             ps_svc_lyr_dec->ps_subset_sps[u1_seq_parameter_set_id].s_sps_svc_ext.ps_svc_vui_ext;
     }
     ps_svc_lyr_dec->ps_subset_sps[u1_seq_parameter_set_id] = *ps_subset_seq;
-    ps_dec->ps_cur_sps = &ps_dec->ps_sps[u1_seq_parameter_set_id];
     ps_svc_lyr_dec->ps_cur_subset_sps = &ps_svc_lyr_dec->ps_subset_sps[u1_seq_parameter_set_id];
 
     return OK;
@@ -1186,14 +1157,6 @@ WORD32 isvcd_parse_sps(svc_dec_lyr_struct_t *ps_svc_lyr_dec, dec_bit_stream_t *p
     ps_seq = ps_dec->pv_scratch_sps_pps;
     memset(ps_seq, 0, sizeof(dec_seq_params_t));
 
-    if(ps_dec->i4_header_decoded & 1)
-    {
-        if(ps_dec->ps_cur_sps != NULL)
-            *ps_seq = *ps_dec->ps_cur_sps;
-        else
-            return ERROR_INV_SPS_PPS_T;
-    }
-
     if((ps_dec->i4_header_decoded & 1) &&
        (1 == ps_dec->ps_sps[u1_seq_parameter_set_id].u1_is_valid) &&
        (ps_dec->ps_sps[u1_seq_parameter_set_id].u1_profile_idc != u1_profile_idc))
@@ -1404,6 +1367,15 @@ WORD32 isvcd_parse_sps(svc_dec_lyr_struct_t *ps_svc_lyr_dec, dec_bit_stream_t *p
     ps_seq->u2_frm_ht_in_mbs = u4_pic_height_in_map_units;
     u2_pic_wd = (u4_pic_width_in_mbs << 4);
     u2_pic_ht = (u4_pic_height_in_map_units << 4);
+    if(ps_svc_lyr_dec->pic_width < u2_pic_wd)
+    {
+        ps_svc_lyr_dec->pic_width = u2_pic_wd;
+    }
+    if(ps_svc_lyr_dec->pic_height < u2_pic_ht)
+    {
+        ps_svc_lyr_dec->pic_height = u2_pic_ht;
+    }
+
     /*--------------------------------------------------------------------*/
     /* Get the value of MaxMbAddress and Number of bits needed for it     */
     /*--------------------------------------------------------------------*/
@@ -1639,37 +1611,9 @@ WORD32 isvcd_parse_sps(svc_dec_lyr_struct_t *ps_svc_lyr_dec, dec_bit_stream_t *p
     ps_subset_seq->u2_crop_offset_y = u2_crop_offset_y;
     ps_subset_seq->u2_crop_offset_uv = u2_crop_offset_uv;
 
-    if(((ps_dec->u2_pic_wd * ps_dec->u2_pic_ht) <
-        (ps_subset_seq->u2_pic_wd * ps_subset_seq->u2_pic_ht)) ||
-       (ps_dec->i4_reorder_depth < ps_subset_seq->i4_reorder_depth))
-    {
-        ps_dec->i4_reorder_depth = ps_subset_seq->i4_reorder_depth;
-
-        ps_dec->u2_disp_height = ps_subset_seq->u2_disp_height;
-        ps_dec->u2_disp_width = ps_subset_seq->u2_disp_width;
-        ps_dec->u2_pic_wd = ps_subset_seq->u2_pic_wd;
-        ps_dec->u2_pic_ht = ps_subset_seq->u2_pic_ht;
-        ps_dec->u4_total_mbs = ps_seq->u2_total_num_of_mbs << (1 - ps_seq->u1_frame_mbs_only_flag);
-
-        /* Determining the Width and Height of Frame from that of Picture */
-        ps_dec->u2_frm_wd_y = ps_subset_seq->u2_frm_wd_y;
-        ps_dec->u2_frm_ht_y = ps_subset_seq->u2_frm_ht_y;
-        ps_dec->u2_frm_wd_uv = ps_subset_seq->u2_frm_wd_uv;
-        ps_dec->u2_frm_ht_uv = ps_subset_seq->u2_frm_ht_uv;
-
-        ps_dec->s_pad_mgr.u1_pad_len_y_v = ps_subset_seq->u1_pad_len_y_v;
-        ps_dec->s_pad_mgr.u1_pad_len_cr_v = ps_subset_seq->u1_pad_len_cr_v;
-
-        ps_dec->u2_frm_wd_in_mbs = ps_seq->u2_frm_wd_in_mbs;
-        ps_dec->u2_frm_ht_in_mbs = ps_seq->u2_frm_ht_in_mbs;
-        ps_dec->u2_crop_offset_y = ps_subset_seq->u2_crop_offset_y;
-        ps_dec->u2_crop_offset_uv = ps_subset_seq->u2_crop_offset_uv;
-    }
-
     ps_seq->u1_is_valid = TRUE;
     ps_dec->ps_sps[u1_seq_parameter_set_id] = *ps_seq;
     ps_svc_lyr_dec->ps_subset_sps[u1_seq_parameter_set_id] = *ps_subset_seq;
-    ps_dec->ps_cur_sps = &ps_dec->ps_sps[u1_seq_parameter_set_id];
     ps_svc_lyr_dec->ps_cur_subset_sps = &ps_svc_lyr_dec->ps_subset_sps[u1_seq_parameter_set_id];
 
     return OK;
diff --git a/decoder/svc/isvcd_structs.h b/decoder/svc/isvcd_structs.h
index fefd32d..85f1295 100644
--- a/decoder/svc/isvcd_structs.h
+++ b/decoder/svc/isvcd_structs.h
@@ -661,6 +661,8 @@ typedef struct _SvcDecLyrStruct
     UWORD32 u4_pps_id_for_layer;
     UWORD8 u1_error_in_cur_frame;
     UWORD8 u1_res_init_done;
+    WORD32 pic_width;
+    WORD32 pic_height;
 } svc_dec_lyr_struct_t;
 
 typedef struct
@@ -720,6 +722,8 @@ typedef struct
     UWORD8 u1_parse_nal_unit_error;
     UWORD8 u1_exit_till_next_IDR;
     UWORD8 u1_pre_parse_in_flush;
+    WORD32 pic_width;
+    WORD32 pic_height;
 } svc_dec_ctxt_t;
 
 #endif /*_ISVCD_STRUCTS_H_*/
\ No newline at end of file