Commit message: [trunk] Correct potential double free on malloc failure in opj_j2k_copy_default_tcp_and_create_tcp (fixes issue 492)
CVE: CVE-2015-6581
CWE: NVD-CWE-Other
Vulnerability description: Double free vulnerability in the opj_j2k_copy_default_tcp_and_create_tcd function in j2k.c in OpenJPEG before r3002, as used in PDFium in Google Chrome before 45.0.2454.85, allows remote attackers to execute arbitrary code or cause a denial of service (heap memory corruption) by triggering a memory-allocation failure.

Project: openjpeg
File: j2k.c

OPJ_BOOL opj_j2k_read_mcc (     opj_j2k_t *p_j2k,
                                                OPJ_BYTE * p_header_data,
                                                OPJ_UINT32 p_header_size,
                                                opj_event_mgr_t * p_manager )
{
        OPJ_UINT32 i,j;
        OPJ_UINT32 l_tmp;
        OPJ_UINT32 l_indix;
        opj_tcp_t * l_tcp;
        opj_simple_mcc_decorrelation_data_t * l_mcc_record;
        opj_mct_data_t * l_mct_data;
        OPJ_UINT32 l_nb_collections;
        OPJ_UINT32 l_nb_comps;
        OPJ_UINT32 l_nb_bytes_by_comp;

        /* preconditions */
        assert(p_header_data != 00);
        assert(p_j2k != 00);
        assert(p_manager != 00);

        l_tcp = p_j2k->m_specific_param.m_decoder.m_state == J2K_STATE_TPH ?
                        &p_j2k->m_cp.tcps[p_j2k->m_current_tile_number] :
                        p_j2k->m_specific_param.m_decoder.m_default_tcp;

        if (p_header_size < 2) {
                opj_event_msg(p_manager, EVT_ERROR, "Error reading MCC marker\n");
                return OPJ_FALSE;
        }

        /* first marker */
        opj_read_bytes(p_header_data,&l_tmp,2);                         /* Zmcc */
        p_header_data += 2;
        if (l_tmp != 0) {
                opj_event_msg(p_manager, EVT_WARNING, "Cannot take in charge multiple data spanning\n");
                return OPJ_TRUE;
        }

        if (p_header_size < 7) {
                opj_event_msg(p_manager, EVT_ERROR, "Error reading MCC marker\n");
                return OPJ_FALSE;
        }

        opj_read_bytes(p_header_data,&l_indix,1); /* Imcc -> no need for other values, take the first */
        ++p_header_data;

        l_mcc_record = l_tcp->m_mcc_records;

        for(i=0;i<l_tcp->m_nb_mcc_records;++i) {
                if (l_mcc_record->m_index == l_indix) {
                        break;
                }
                ++l_mcc_record;
        }

        /** NOT FOUND */
        if (i == l_tcp->m_nb_mcc_records) {
                if (l_tcp->m_nb_mcc_records == l_tcp->m_nb_max_mcc_records) {
                        opj_simple_mcc_decorrelation_data_t *new_mcc_records;
                        l_tcp->m_nb_max_mcc_records += OPJ_J2K_MCC_DEFAULT_NB_RECORDS;

                        new_mcc_records = (opj_simple_mcc_decorrelation_data_t *) opj_realloc(
                                        l_tcp->m_mcc_records, l_tcp->m_nb_max_mcc_records * sizeof(opj_simple_mcc_decorrelation_data_t));
                        if (! new_mcc_records) {
                                opj_free(l_tcp->m_mcc_records);
                                l_tcp->m_mcc_records = NULL;
                                l_tcp->m_nb_max_mcc_records = 0;
                                l_tcp->m_nb_mcc_records = 0;
                                opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to read MCC marker\n");
                                return OPJ_FALSE;
                        }
                        l_tcp->m_mcc_records = new_mcc_records;
                        l_mcc_record = l_tcp->m_mcc_records + l_tcp->m_nb_mcc_records;
                        memset(l_mcc_record,0,(l_tcp->m_nb_max_mcc_records-l_tcp->m_nb_mcc_records) * sizeof(opj_simple_mcc_decorrelation_data_t));
                }
                l_mcc_record = l_tcp->m_mcc_records + l_tcp->m_nb_mcc_records;
        }
        l_mcc_record->m_index = l_indix;

        /* only one marker atm */
        opj_read_bytes(p_header_data,&l_tmp,2);                         /* Ymcc */
        p_header_data+=2;
        if (l_tmp != 0) {
                opj_event_msg(p_manager, EVT_WARNING, "Cannot take in charge multiple data spanning\n");
                return OPJ_TRUE;
        }

        opj_read_bytes(p_header_data,&l_nb_collections,2);                              /* Qmcc -> number of collections -> 1 */
        p_header_data+=2;

        if (l_nb_collections > 1) {
                opj_event_msg(p_manager, EVT_WARNING, "Cannot take in charge multiple collections\n");
                return OPJ_TRUE;
        }

        p_header_size -= 7;

        for (i=0;i<l_nb_collections;++i) {
                if (p_header_size < 3) {
                        opj_event_msg(p_manager, EVT_ERROR, "Error reading MCC marker\n");
                        return OPJ_FALSE;
                }

                opj_read_bytes(p_header_data,&l_tmp,1); /* Xmcci type of component transformation -> array based decorrelation */
                ++p_header_data;

                if (l_tmp != 1) {
                        opj_event_msg(p_manager, EVT_WARNING, "Cannot take in charge collections other than array decorrelation\n");
                        return OPJ_TRUE;
                }

                opj_read_bytes(p_header_data,&l_nb_comps,2);

                p_header_data+=2;
                p_header_size-=3;

                l_nb_bytes_by_comp = 1 + (l_nb_comps>>15);
                l_mcc_record->m_nb_comps = l_nb_comps & 0x7fff;

                if (p_header_size < (l_nb_bytes_by_comp * l_mcc_record->m_nb_comps + 2)) {
                        opj_event_msg(p_manager, EVT_ERROR, "Error reading MCC marker\n");
                        return OPJ_FALSE;
                }

                p_header_size -= (l_nb_bytes_by_comp * l_mcc_record->m_nb_comps + 2);

                for (j=0;j<l_mcc_record->m_nb_comps;++j) {
                        opj_read_bytes(p_header_data,&l_tmp,l_nb_bytes_by_comp);        /* Cmccij Component offset*/
                        p_header_data+=l_nb_bytes_by_comp;

                        if (l_tmp != j) {
                                opj_event_msg(p_manager, EVT_WARNING, "Cannot take in charge collections with indix shuffle\n");
                                return OPJ_TRUE;
                        }
                }

                opj_read_bytes(p_header_data,&l_nb_comps,2);
                p_header_data+=2;

                l_nb_bytes_by_comp = 1 + (l_nb_comps>>15);
                l_nb_comps &= 0x7fff;

                if (l_nb_comps != l_mcc_record->m_nb_comps) {
                        opj_event_msg(p_manager, EVT_WARNING, "Cannot take in charge collections without same number of indixes\n");
                        return OPJ_TRUE;
                }

                if (p_header_size < (l_nb_bytes_by_comp * l_mcc_record->m_nb_comps + 3)) {
                        opj_event_msg(p_manager, EVT_ERROR, "Error reading MCC marker\n");
                        return OPJ_FALSE;
                }

                p_header_size -= (l_nb_bytes_by_comp * l_mcc_record->m_nb_comps + 3);

                for (j=0;j<l_mcc_record->m_nb_comps;++j) {
                        opj_read_bytes(p_header_data,&l_tmp,l_nb_bytes_by_comp);        /* Wmccij Component offset*/
                        p_header_data+=l_nb_bytes_by_comp;

                        if (l_tmp != j) {
                                opj_event_msg(p_manager, EVT_WARNING, "Cannot take in charge collections with indix shuffle\n");
                                return OPJ_TRUE;
                        }
                }

                opj_read_bytes(p_header_data,&l_tmp,3); /* Wmccij Component offset*/
                p_header_data += 3;

                l_mcc_record->m_is_irreversible = ! ((l_tmp>>16) & 1);
                l_mcc_record->m_decorrelation_array = 00;
                l_mcc_record->m_offset_array = 00;

                l_indix = l_tmp & 0xff;
                if (l_indix != 0) {
                        l_mct_data = l_tcp->m_mct_records;
                        for (j=0;j<l_tcp->m_nb_mct_records;++j) {
                                if (l_mct_data->m_index == l_indix) {
                                        l_mcc_record->m_decorrelation_array = l_mct_data;
                                        break;
                                }
                                ++l_mct_data;
                        }

                        if (l_mcc_record->m_decorrelation_array == 00) {
                                opj_event_msg(p_manager, EVT_ERROR, "Error reading MCC marker\n");
                                return OPJ_FALSE;
                        }
                }

                l_indix = (l_tmp >> 8) & 0xff;
                if (l_indix != 0) {
                        l_mct_data = l_tcp->m_mct_records;
                        for (j=0;j<l_tcp->m_nb_mct_records;++j) {
                                if (l_mct_data->m_index == l_indix) {
                                        l_mcc_record->m_offset_array = l_mct_data;
                                        break;
                                }
                                ++l_mct_data;
                        }

                        if (l_mcc_record->m_offset_array == 00) {
                                opj_event_msg(p_manager, EVT_ERROR, "Error reading MCC marker\n");
                                return OPJ_FALSE;
                        }
                }
        }

        if (p_header_size != 0) {
                opj_event_msg(p_manager, EVT_ERROR, "Error reading MCC marker\n");
                return OPJ_FALSE;
        }

        ++l_tcp->m_nb_mcc_records;

        return OPJ_TRUE;
}

Project: openjpeg
File: j2k.c

void opj_j2k_destroy (opj_j2k_t *p_j2k)
{
        if (p_j2k == 00) {
                return;
        }

        if (p_j2k->m_is_decoder) {

                if (p_j2k->m_specific_param.m_decoder.m_default_tcp != 00) {
                        opj_j2k_tcp_destroy(p_j2k->m_specific_param.m_decoder.m_default_tcp);
                        opj_free(p_j2k->m_specific_param.m_decoder.m_default_tcp);
                        p_j2k->m_specific_param.m_decoder.m_default_tcp = 00;
                }

                if (p_j2k->m_specific_param.m_decoder.m_header_data != 00) {
                        opj_free(p_j2k->m_specific_param.m_decoder.m_header_data);
                        p_j2k->m_specific_param.m_decoder.m_header_data = 00;
                        p_j2k->m_specific_param.m_decoder.m_header_data_size = 0;
                }
        }
        else {

                if (p_j2k->m_specific_param.m_encoder.m_encoded_tile_data) {
                        opj_free(p_j2k->m_specific_param.m_encoder.m_encoded_tile_data);
                        p_j2k->m_specific_param.m_encoder.m_encoded_tile_data = 00;
                }

                if (p_j2k->m_specific_param.m_encoder.m_tlm_sot_offsets_buffer) {
                        opj_free(p_j2k->m_specific_param.m_encoder.m_tlm_sot_offsets_buffer);
                        p_j2k->m_specific_param.m_encoder.m_tlm_sot_offsets_buffer = 00;
                        p_j2k->m_specific_param.m_encoder.m_tlm_sot_offsets_current = 00;
                }

                if (p_j2k->m_specific_param.m_encoder.m_header_tile_data) {
                        opj_free(p_j2k->m_specific_param.m_encoder.m_header_tile_data);
                        p_j2k->m_specific_param.m_encoder.m_header_tile_data = 00;
                        p_j2k->m_specific_param.m_encoder.m_header_tile_data_size = 0;
                }
        }

        opj_tcd_destroy(p_j2k->m_tcd);

        opj_j2k_cp_destroy(&(p_j2k->m_cp));
        memset(&(p_j2k->m_cp),0,sizeof(opj_cp_t));

        opj_procedure_list_destroy(p_j2k->m_procedure_list);
        p_j2k->m_procedure_list = 00;

        opj_procedure_list_destroy(p_j2k->m_validation_list);
        p_j2k->m_procedure_list = 00;

        j2k_destroy_cstr_index(p_j2k->cstr_index);
        p_j2k->cstr_index = NULL;

        opj_image_destroy(p_j2k->m_private_image);
        p_j2k->m_private_image = NULL;

        opj_image_destroy(p_j2k->m_output_image);
        p_j2k->m_output_image = NULL;

        opj_free(p_j2k);
}

Project: openjpeg
File: j2k.c

OPJ_BOOL opj_j2k_exec ( opj_j2k_t * p_j2k,
                                        opj_procedure_list_t * p_procedure_list,
                                        opj_stream_private_t *p_stream,
                                        opj_event_mgr_t * p_manager )
{
        OPJ_BOOL (** l_procedure) (opj_j2k_t * ,opj_stream_private_t *,opj_event_mgr_t *) = 00;
        OPJ_BOOL l_result = OPJ_TRUE;
        OPJ_UINT32 l_nb_proc, i;

        /* preconditions*/
        assert(p_procedure_list != 00);
        assert(p_j2k != 00);
        assert(p_stream != 00);
        assert(p_manager != 00);

        l_nb_proc = opj_procedure_list_get_nb_procedures(p_procedure_list);
        l_procedure = (OPJ_BOOL (**) (opj_j2k_t * ,opj_stream_private_t *,opj_event_mgr_t *)) opj_procedure_list_get_first_procedure(p_procedure_list);

        for     (i=0;i<l_nb_proc;++i) {
                l_result = l_result && ((*l_procedure) (p_j2k,p_stream,p_manager));
                ++l_procedure;
        }

        /* and clear the procedure list at the end.*/
        opj_procedure_list_clear(p_procedure_list);
        return l_result;
}

Project: openjpeg
File: j2k.c

void  opj_j2k_read_int32_to_int32 (const void * p_src_data, void * p_dest_data, OPJ_UINT32 p_nb_elem)
{
        OPJ_BYTE * l_src_data = (OPJ_BYTE *) p_src_data;
        OPJ_INT32 * l_dest_data = (OPJ_INT32 *) p_dest_data;
        OPJ_UINT32 i;
        OPJ_UINT32 l_temp;

        for (i=0;i<p_nb_elem;++i) {
                opj_read_bytes(l_src_data,&l_temp,4);

                l_src_data+=sizeof(OPJ_INT32);

                *(l_dest_data++) = (OPJ_INT32) l_temp;
        }
}