summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBo Xu <bo_xu@foxitsoftware.com>2014-10-21 13:05:17 -0700
committerBo Xu <bo_xu@foxitsoftware.com>2014-10-21 13:05:17 -0700
commit767aebbef641a89498deebc29369a078207b4dcc (patch)
treefe4aba016b0150480278fccbd9a938d3e714a29b
parentbff247d92c315f9aab2edb4aeaf0ef0b74ba321f (diff)
downloadpdfium-767aebbef641a89498deebc29369a078207b4dcc.tar.xz
BUG=414089, 414310, 414606 R=tsepez@chromium.org Review URL: https://codereview.chromium.org/670813002
-rw-r--r--core/src/fxcodec/fx_libopenjpeg/libopenjpeg20/j2k.c64
-rw-r--r--core/src/fxcodec/fx_libopenjpeg/libopenjpeg20/jp2.c49
-rw-r--r--core/src/fxcodec/fx_libopenjpeg/libopenjpeg20/t2.c19
3 files changed, 124 insertions, 8 deletions
diff --git a/core/src/fxcodec/fx_libopenjpeg/libopenjpeg20/j2k.c b/core/src/fxcodec/fx_libopenjpeg/libopenjpeg20/j2k.c
index b794dc39a6..93f8a3db63 100644
--- a/core/src/fxcodec/fx_libopenjpeg/libopenjpeg20/j2k.c
+++ b/core/src/fxcodec/fx_libopenjpeg/libopenjpeg20/j2k.c
@@ -2415,9 +2415,19 @@ static OPJ_BOOL opj_j2k_read_cod ( opj_j2k_t *p_j2k,
opj_read_bytes(p_header_data,&l_tcp->csty,1); /* Scod */
++p_header_data;
+ /* Make sure we know how to decode this */
+ if ((l_tcp->csty & ~(OPJ_UINT32)(J2K_CP_CSTY_PRT | J2K_CP_CSTY_SOP | J2K_CP_CSTY_EPH)) != 0U) {
+ opj_event_msg(p_manager, EVT_ERROR, "Unknown Scod value in COD marker\n");
+ return OPJ_FALSE;
+ }
opj_read_bytes(p_header_data,&l_tmp,1); /* SGcod (A) */
++p_header_data;
l_tcp->prg = (OPJ_PROG_ORDER) l_tmp;
+ /* Make sure progression order is valid */
+ if (l_tcp->prg > OPJ_CPRL ) {
+ opj_event_msg(p_manager, EVT_ERROR, "Unknown progression order in COD marker\n");
+ l_tcp->prg = OPJ_PROG_UNKNOWN;
+ }
opj_read_bytes(p_header_data,&l_tcp->numlayers,2); /* SGcod (B) */
p_header_data+=2;
@@ -3544,6 +3554,14 @@ OPJ_BOOL j2k_read_ppm_v3 (
/* First PPM marker */
if (l_Z_ppm == 0) {
+ if (l_cp->ppm_data != NULL) {
+ opj_event_msg(p_manager, EVT_ERROR, "Zppm O already processed. Found twice.\n");
+ opj_free(l_cp->ppm_data);
+ l_cp->ppm_data = NULL;
+ l_cp->ppm_buffer = NULL;
+ l_cp->ppm = 0; /* do not use PPM */
+ return OPJ_FALSE;
+ }
/* We need now at least the Nppm^0 element */
if (p_header_size < 4) {
opj_event_msg(p_manager, EVT_ERROR, "Error reading PPM marker\n");
@@ -3641,6 +3659,15 @@ OPJ_BOOL j2k_read_ppm_v3 (
if (p_header_size)
{
+ if (p_header_size < 4) {
+ opj_free(l_cp->ppm_data);
+ l_cp->ppm_data = NULL;
+ l_cp->ppm_buffer = NULL; /* TODO: no need for a new local variable: ppm_buffer and ppm_data are enough */
+ l_cp->ppm_len = 0;
+ l_cp->ppm = 0;
+ opj_event_msg(p_manager, EVT_ERROR, "Error reading PPM marker\n");
+ return OPJ_FALSE;
+ }
opj_read_bytes(p_header_data,&l_N_ppm,4); /* N_ppm^i */
p_header_data+=4;
p_header_size-=4;
@@ -4317,6 +4344,12 @@ OPJ_BOOL opj_j2k_read_sod (opj_j2k_t *p_j2k,
/* Patch to support new PHR data */
if (p_j2k->m_specific_param.m_decoder.m_sot_length) {
+ /* If we are here, we'll try to read the data after allocation */
+ /* Check enough bytes left in stream before allocation */
+ if ((OPJ_OFF_T)p_j2k->m_specific_param.m_decoder.m_sot_length > opj_stream_get_number_byte_left(p_stream)) {
+ opj_event_msg(p_manager, EVT_ERROR, "Tile part length size inconsistent with stream length\n");
+ return OPJ_FALSE;
+ }
if (! *l_current_data) {
/* LH: oddly enough, in this path, l_tile_len!=0.
* TODO: If this was consistant, we could simplify the code to only use realloc(), as realloc(0,...) default to malloc(0,...).
@@ -6117,6 +6150,11 @@ OPJ_BOOL opj_j2k_setup_encoder( opj_j2k_t *p_j2k,
return OPJ_FALSE;
}
+ if ((parameters->numresolution <= 0) || (parameters->numresolution > OPJ_J2K_MAXRLVLS)) {
+ opj_event_msg(p_manager, EVT_ERROR, "Invalid number of resolutions : %d not in range [1,%d]\n", parameters->numresolution, OPJ_J2K_MAXRLVLS);
+ return OPJ_FALSE;
+ }
+
/* keep a link to cp so that we can destroy it later in j2k_destroy_compress */
cp = &(p_j2k->m_cp);
@@ -6504,7 +6542,7 @@ OPJ_BOOL opj_j2k_setup_encoder( opj_j2k_t *p_j2k,
}
}
else {
- if(tcp->mct==1 && image->numcomps == 3) { // RGB->YCC MCT is enabled
+ if(tcp->mct==1 && image->numcomps == 3) { /* RGB->YCC MCT is enabled */
if ((image->comps[0].dx != image->comps[1].dx) ||
(image->comps[0].dx != image->comps[2].dx) ||
(image->comps[0].dy != image->comps[1].dy) ||
@@ -6992,6 +7030,15 @@ OPJ_BOOL opj_j2k_encoding_validation ( opj_j2k_t * p_j2k,
/* make sure a validation list is present */
l_is_valid &= (p_j2k->m_validation_list != 00);
+ /* ISO 15444-1:2004 states between 1 & 33 (0 -> 32) */
+ /* 33 (32) would always fail the 2 checks below (if a cast to 64bits was done) */
+ /* 32 (31) would always fail the 2 checks below (if a cast to 64bits was done) */
+ /* FIXME Shall we change OPJ_J2K_MAXRLVLS to 31 ? */
+ if ((p_j2k->m_cp.tcps->tccps->numresolutions <= 0) || (p_j2k->m_cp.tcps->tccps->numresolutions > 31)) {
+ opj_event_msg(p_manager, EVT_ERROR, "Number of resolutions is too high in comparison to the size of tiles\n");
+ return OPJ_FALSE;
+ }
+
if ((p_j2k->m_cp.tdx) < (OPJ_UINT32) (1 << p_j2k->m_cp.tcps->tccps->numresolutions)) {
opj_event_msg(p_manager, EVT_ERROR, "Number of resolutions is too high in comparison to the size of tiles\n");
return OPJ_FALSE;
@@ -7590,6 +7637,12 @@ OPJ_BOOL opj_j2k_read_tile_header( opj_j2k_t * p_j2k,
/* Read 2 bytes from the buffer as the marker size */
opj_read_bytes(p_j2k->m_specific_param.m_decoder.m_header_data,&l_marker_size,2);
+ /* Check marker size (does not include marker ID but includes marker size) */
+ if (l_marker_size < 2) {
+ opj_event_msg(p_manager, EVT_ERROR, "Inconsistent marker size\n");
+ return OPJ_FALSE;
+ }
+
/* cf. https://code.google.com/p/openjpeg/issues/detail?id=226 */
if (l_current_marker == 0x8080 && opj_stream_get_number_byte_left(p_stream) == 0) {
p_j2k->m_specific_param.m_decoder.m_state = J2K_STATE_NEOC;
@@ -7614,7 +7667,14 @@ OPJ_BOOL opj_j2k_read_tile_header( opj_j2k_t * p_j2k,
/* Check if the marker size is compatible with the header data size */
if (l_marker_size > p_j2k->m_specific_param.m_decoder.m_header_data_size) {
- OPJ_BYTE *new_header_data = (OPJ_BYTE *) opj_realloc(p_j2k->m_specific_param.m_decoder.m_header_data, l_marker_size);
+ OPJ_BYTE *new_header_data = NULL;
+ /* If we are here, this means we consider this marker as known & we will read it */
+ /* Check enough bytes left in stream before allocation */
+ if ((OPJ_OFF_T)l_marker_size > opj_stream_get_number_byte_left(p_stream)) {
+ opj_event_msg(p_manager, EVT_ERROR, "Marker size inconsistent with stream length\n");
+ return OPJ_FALSE;
+ }
+ new_header_data = (OPJ_BYTE *) opj_realloc(p_j2k->m_specific_param.m_decoder.m_header_data, l_marker_size);
if (! new_header_data) {
opj_free(p_j2k->m_specific_param.m_decoder.m_header_data);
p_j2k->m_specific_param.m_decoder.m_header_data = NULL;
diff --git a/core/src/fxcodec/fx_libopenjpeg/libopenjpeg20/jp2.c b/core/src/fxcodec/fx_libopenjpeg/libopenjpeg20/jp2.c
index 683d0415cf..78a15026a9 100644
--- a/core/src/fxcodec/fx_libopenjpeg/libopenjpeg20/jp2.c
+++ b/core/src/fxcodec/fx_libopenjpeg/libopenjpeg20/jp2.c
@@ -764,6 +764,12 @@ static OPJ_BOOL opj_jp2_check_color(opj_image_t *image, opj_jp2_color_t *color,
if (color->jp2_cdef) {
opj_jp2_cdef_info_t *info = color->jp2_cdef->info;
OPJ_UINT16 n = color->jp2_cdef->n;
+ OPJ_UINT32 nr_channels = image->numcomps; /* FIXME image->numcomps == jp2->numcomps before color is applied ??? */
+
+ /* cdef applies to cmap channels if any */
+ if (color->jp2_pclr && color->jp2_pclr->cmap) {
+ nr_channels = (OPJ_UINT32)color->jp2_pclr->nr_channels;
+ }
for (i = 0; i < n; i++) {
if (info[i].cn >= image->numcomps) {
@@ -775,6 +781,22 @@ static OPJ_BOOL opj_jp2_check_color(opj_image_t *image, opj_jp2_color_t *color,
return OPJ_FALSE;
}
}
+
+ /* issue 397 */
+ /* ISO 15444-1 states that if cdef is present, it shall contain a complete list of channel definitions. */
+ while (nr_channels > 0)
+ {
+ for(i = 0; i < n; ++i) {
+ if ((OPJ_UINT32)info[i].cn == (nr_channels - 1U)) {
+ break;
+ }
+ }
+ if (i == n) {
+ opj_event_msg(p_manager, EVT_ERROR, "Incomplete channel definitions.\n");
+ return OPJ_FALSE;
+ }
+ --nr_channels;
+ }
}
/* testcases 451.pdf.SIGSEGV.f4c.3723, 451.pdf.SIGSEGV.5b5.3723 and
@@ -1017,7 +1039,7 @@ OPJ_BOOL opj_jp2_read_pclr( opj_jp2_t *jp2,
if (bytes_to_read > sizeof(OPJ_UINT32))
bytes_to_read = sizeof(OPJ_UINT32);
- if ((ptrdiff_t)p_pclr_header_size < p_pclr_header_data - orig_header_data + (ptrdiff_t)bytes_to_read)
+ if ((ptrdiff_t)p_pclr_header_size < (ptrdiff_t)(p_pclr_header_data - orig_header_data) + (ptrdiff_t)bytes_to_read)
return OPJ_FALSE;
opj_read_bytes(p_pclr_header_data, &l_value , bytes_to_read); /* Cji */
@@ -1280,7 +1302,7 @@ OPJ_BOOL opj_jp2_read_colr( opj_jp2_t *jp2,
}
else if (jp2->meth > 2)
{
- /* ISO/IEC 15444-1:2004 (E), Table I.9 Legal METH values:
+ /* ISO/IEC 15444-1:2004 (E), Table I.9 Legal METH values:
conforming JP2 reader shall ignore the entire Colour Specification box.*/
opj_event_msg(p_manager, EVT_INFO, "COLR BOX meth value is not a regular value (%d), "
"so we will ignore the entire Colour Specification box. \n", jp2->meth);
@@ -1843,7 +1865,7 @@ OPJ_BOOL opj_jp2_read_header_procedure( opj_jp2_t *jp2,
return OPJ_FALSE;
}
/* testcase 1851.pdf.SIGSEGV.ce9.948 */
- else if (box.length < l_nb_bytes_read) {
+ else if (box.length < l_nb_bytes_read) {
opj_event_msg(p_manager, EVT_ERROR, "invalid box size %d (%x)\n", box.length, box.type);
opj_free(l_current_data);
return OPJ_FALSE;
@@ -1853,6 +1875,12 @@ OPJ_BOOL opj_jp2_read_header_procedure( opj_jp2_t *jp2,
l_current_data_size = box.length - l_nb_bytes_read;
if (l_current_handler != 00) {
+ if ((OPJ_OFF_T)l_current_data_size > opj_stream_get_number_byte_left(stream)) {
+ /* do not even try to malloc if we can't read */
+ opj_event_msg(p_manager, EVT_ERROR, "Invalid box size %d for box '%c%c%c%c'. Need %d bytes, %d bytes remaining \n", box.length, (OPJ_BYTE)(box.type>>24), (OPJ_BYTE)(box.type>>16), (OPJ_BYTE)(box.type>>8), (OPJ_BYTE)(box.type>>0), l_current_data_size, (OPJ_UINT32)opj_stream_get_number_byte_left(stream));
+ opj_free(l_current_data);
+ return OPJ_FALSE;
+ }
if (l_current_data_size > l_last_data_size) {
OPJ_BYTE* new_current_data = (OPJ_BYTE*)opj_realloc(l_current_data,l_current_data_size);
if (!new_current_data) {
@@ -2164,6 +2192,7 @@ static OPJ_BOOL opj_jp2_read_jp2h( opj_jp2_t *jp2,
OPJ_UINT32 l_box_size=0, l_current_data_size = 0;
opj_jp2_box_t box;
const opj_jp2_header_handler_t * l_current_handler;
+ OPJ_BOOL l_has_ihdr = 0;
/* preconditions */
assert(p_header_data != 00);
@@ -2204,10 +2233,19 @@ static OPJ_BOOL opj_jp2_read_jp2h( opj_jp2_t *jp2,
jp2->jp2_img_state |= JP2_IMG_STATE_UNKNOWN;
}
+ if (box.type == JP2_IHDR) {
+ l_has_ihdr = 1;
+ }
+
p_header_data += l_current_data_size;
p_header_size -= box.length;
}
+ if (l_has_ihdr == 0) {
+ opj_event_msg(p_manager, EVT_ERROR, "Stream error while reading JP2 Header box: no 'ihdr' box.\n");
+ return OPJ_FALSE;
+ }
+
jp2->jp2_state |= JP2_STATE_HEADER;
return OPJ_TRUE;
@@ -2276,7 +2314,10 @@ OPJ_BOOL opj_jp2_read_boxhdr_char( opj_jp2_box_t *box,
opj_event_msg(p_manager, EVT_ERROR, "Cannot handle box of undefined sizes\n");
return OPJ_FALSE;
}
-
+ if (box->length < *p_number_bytes_read) {
+ opj_event_msg(p_manager, EVT_ERROR, "Box length is inconsistent.\n");
+ return OPJ_FALSE;
+ }
return OPJ_TRUE;
}
diff --git a/core/src/fxcodec/fx_libopenjpeg/libopenjpeg20/t2.c b/core/src/fxcodec/fx_libopenjpeg/libopenjpeg20/t2.c
index cdd35e8c22..1a29cccfc6 100644
--- a/core/src/fxcodec/fx_libopenjpeg/libopenjpeg20/t2.c
+++ b/core/src/fxcodec/fx_libopenjpeg/libopenjpeg20/t2.c
@@ -242,6 +242,11 @@ OPJ_BOOL opj_t2_encode_packets( opj_t2_t* p_t2,
/* TODO MSD : check why this function cannot fail (cf. v1) */
opj_pi_create_encode(l_pi, l_cp,p_tile_no,poc,l_tp_num,p_tp_pos,p_t2_mode);
+ if (l_current_pi->poc.prg == OPJ_PROG_UNKNOWN) {
+ /* TODO ADE : add an error */
+ opj_pi_destroy(l_pi, l_nb_pocs);
+ return OPJ_FALSE;
+ }
while (opj_pi_next(l_current_pi)) {
if (l_current_pi->layno < p_maxlayers) {
l_nb_bytes = 0;
@@ -274,7 +279,11 @@ OPJ_BOOL opj_t2_encode_packets( opj_t2_t* p_t2,
opj_pi_create_encode(l_pi, l_cp,p_tile_no,p_pino,p_tp_num,p_tp_pos,p_t2_mode);
l_current_pi = &l_pi[p_pino];
-
+ if (l_current_pi->poc.prg == OPJ_PROG_UNKNOWN) {
+ /* TODO ADE : add an error */
+ opj_pi_destroy(l_pi, l_nb_pocs);
+ return OPJ_FALSE;
+ }
while (opj_pi_next(l_current_pi)) {
if (l_current_pi->layno < p_maxlayers) {
l_nb_bytes=0;
@@ -386,6 +395,11 @@ OPJ_BOOL opj_t2_decode_packets( opj_t2_t *p_t2,
}
memset(first_pass_failed, OPJ_TRUE, l_image->numcomps * sizeof(OPJ_BOOL));
+ if (l_current_pi->poc.prg == OPJ_PROG_UNKNOWN) {
+ /* TODO ADE : add an error */
+ opj_pi_destroy(l_pi, l_nb_pocs);
+ return OPJ_FALSE;
+ }
while (opj_pi_next(l_current_pi)) {
JAS_FPRINTF( stderr, "packet offset=00000166 prg=%d cmptno=%02d rlvlno=%02d prcno=%03d lyrno=%02d\n\n",
l_current_pi->poc.prg1, l_current_pi->compno, l_current_pi->resno, l_current_pi->precno, l_current_pi->layno );
@@ -1265,7 +1279,8 @@ OPJ_BOOL opj_t2_skip_packet_data( opj_t2_t* p_t2,
}
do {
- if (* p_data_read + l_seg->newlen > p_max_length) {
+ /* Check possible overflow then size */
+ if (((*p_data_read + l_seg->newlen) < (*p_data_read)) || ((*p_data_read + l_seg->newlen) > p_max_length)) {
fprintf(stderr, "skip: segment too long (%d) with max (%d) for codeblock %d (p=%d, b=%d, r=%d, c=%d)\n",
l_seg->newlen, p_max_length, cblkno, p_pi->precno, bandno, p_pi->resno, p_pi->compno);
return OPJ_FALSE;