diff options
-rw-r--r-- | core/fxcodec/codec/ccodec_gifmodule.cpp | 2 | ||||
-rw-r--r-- | core/fxcodec/codec/ccodec_progressivedecoder.h | 2 | ||||
-rw-r--r-- | core/fxcodec/codec/fx_codec_progress.cpp | 44 | ||||
-rw-r--r-- | core/fxcodec/fx_codec_def.h | 1 | ||||
-rw-r--r-- | core/fxcodec/lgif/cgifcontext.cpp | 2 | ||||
-rw-r--r-- | core/fxcodec/lgif/cgifcontext.h | 2 | ||||
-rw-r--r-- | core/fxcodec/lgif/fx_gif.cpp | 32 | ||||
-rw-r--r-- | core/fxcodec/lgif/fx_gif.h | 7 | ||||
-rw-r--r-- | testing/libfuzzer/xfa_codec_fuzzer.h | 2 | ||||
-rw-r--r-- | xfa/fxfa/cxfa_ffimage.cpp | 3 | ||||
-rw-r--r-- | xfa/fxfa/cxfa_ffpageview.cpp | 3 | ||||
-rw-r--r-- | xfa/fxfa/cxfa_ffwidget.cpp | 38 |
12 files changed, 91 insertions, 47 deletions
diff --git a/core/fxcodec/codec/ccodec_gifmodule.cpp b/core/fxcodec/codec/ccodec_gifmodule.cpp index f7e3546a8f..911323c3a1 100644 --- a/core/fxcodec/codec/ccodec_gifmodule.cpp +++ b/core/fxcodec/codec/ccodec_gifmodule.cpp @@ -36,7 +36,7 @@ GifDecodeStatus CCodec_GifModule::ReadHeader(Context* pContext, *width = context->width; *height = context->height; - *pal_num = context->global_pal_num; + *pal_num = (2 << context->global_pal_exp); *pal_pp = context->m_GlobalPalette.empty() ? nullptr : context->m_GlobalPalette.data(); *bg_index = context->bc_index; diff --git a/core/fxcodec/codec/ccodec_progressivedecoder.h b/core/fxcodec/codec/ccodec_progressivedecoder.h index 87bed08fcf..05b7c92078 100644 --- a/core/fxcodec/codec/ccodec_progressivedecoder.h +++ b/core/fxcodec/codec/ccodec_progressivedecoder.h @@ -56,7 +56,7 @@ class CCodec_ProgressiveDecoder : public CCodec_BmpModule::Delegate, int32_t GetBPC() const { return m_SrcBPC; } void SetClipBox(FX_RECT* clip); - FXCODEC_STATUS GetFrames(int32_t& frames); + FXCODEC_STATUS GetFrames(int32_t* frames); FXCODEC_STATUS StartDecode(const RetainPtr<CFX_DIBitmap>& pDIBitmap, int start_x, int start_y, diff --git a/core/fxcodec/codec/fx_codec_progress.cpp b/core/fxcodec/codec/fx_codec_progress.cpp index 8b90d3ab84..f10523cc39 100644 --- a/core/fxcodec/codec/fx_codec_progress.cpp +++ b/core/fxcodec/codec/fx_codec_progress.cpp @@ -1791,7 +1791,7 @@ void CCodec_ProgressiveDecoder::Resample( } } -FXCODEC_STATUS CCodec_ProgressiveDecoder::GetFrames(int32_t& frames) { +FXCODEC_STATUS CCodec_ProgressiveDecoder::GetFrames(int32_t* frames) { if (!(m_status == FXCODEC_STATUS_FRAME_READY || m_status == FXCODEC_STATUS_FRAME_TOBECONTINUE)) { return FXCODEC_STATUS_ERROR; @@ -1801,7 +1801,8 @@ FXCODEC_STATUS CCodec_ProgressiveDecoder::GetFrames(int32_t& frames) { case FXCODEC_IMAGE_BMP: case FXCODEC_IMAGE_PNG: case FXCODEC_IMAGE_TIF: - frames = m_FrameNumber = 1; + *frames = 1; + m_FrameNumber = 1; m_status = FXCODEC_STATUS_DECODE_READY; return m_status; case FXCODEC_IMAGE_GIF: { @@ -1822,7 +1823,7 @@ FXCODEC_STATUS CCodec_ProgressiveDecoder::GetFrames(int32_t& frames) { pGifModule->LoadFrameInfo(m_pGifContext.get(), &m_FrameNumber); } if (readResult == GifDecodeStatus::Success) { - frames = m_FrameNumber; + *frames = m_FrameNumber; m_status = FXCODEC_STATUS_DECODE_READY; return m_status; } @@ -2108,34 +2109,37 @@ FXCODEC_STATUS CCodec_ProgressiveDecoder::ContinueDecode() { case FXCODEC_IMAGE_GIF: { CCodec_GifModule* pGifModule = m_pCodecMgr->GetGifModule(); if (!pGifModule) { + m_pDeviceBitmap = nullptr; + m_pFile = nullptr; m_status = FXCODEC_STATUS_ERR_MEMORY; return m_status; } - while (true) { - GifDecodeStatus readRes = - pGifModule->LoadFrame(m_pGifContext.get(), m_FrameCur, nullptr); - while (readRes == GifDecodeStatus::Unfinished) { - FXCODEC_STATUS error_status = FXCODEC_STATUS_DECODE_FINISH; - if (!GifReadMoreData(pGifModule, error_status)) { - m_pDeviceBitmap = nullptr; - m_pFile = nullptr; - m_status = error_status; - return m_status; - } - readRes = - pGifModule->LoadFrame(m_pGifContext.get(), m_FrameCur, nullptr); - } - if (readRes == GifDecodeStatus::Success) { + + GifDecodeStatus readRes = + pGifModule->LoadFrame(m_pGifContext.get(), m_FrameCur, nullptr); + while (readRes == GifDecodeStatus::Unfinished) { + FXCODEC_STATUS error_status = FXCODEC_STATUS_DECODE_FINISH; + if (!GifReadMoreData(pGifModule, error_status)) { m_pDeviceBitmap = nullptr; m_pFile = nullptr; - m_status = FXCODEC_STATUS_DECODE_FINISH; + m_status = error_status; return m_status; } + readRes = + pGifModule->LoadFrame(m_pGifContext.get(), m_FrameCur, nullptr); + } + + if (readRes == GifDecodeStatus::Success) { m_pDeviceBitmap = nullptr; m_pFile = nullptr; - m_status = FXCODEC_STATUS_ERROR; + m_status = FXCODEC_STATUS_DECODE_FINISH; return m_status; } + + m_pDeviceBitmap = nullptr; + m_pFile = nullptr; + m_status = FXCODEC_STATUS_ERROR; + return m_status; } case FXCODEC_IMAGE_BMP: { CCodec_BmpModule* pBmpModule = m_pCodecMgr->GetBmpModule(); diff --git a/core/fxcodec/fx_codec_def.h b/core/fxcodec/fx_codec_def.h index fd23d78fa5..04696a11dd 100644 --- a/core/fxcodec/fx_codec_def.h +++ b/core/fxcodec/fx_codec_def.h @@ -22,6 +22,7 @@ enum FXCODEC_STATUS { FXCODEC_STATUS_ERR_FORMAT, FXCODEC_STATUS_ERR_PARAMS }; + #define JP2_SPACE_INVALID -1 #define JPX_SPACE_INVALID -1 #define JP2_SPACE_bilevel1 0 diff --git a/core/fxcodec/lgif/cgifcontext.cpp b/core/fxcodec/lgif/cgifcontext.cpp index e57e978218..4dc663644c 100644 --- a/core/fxcodec/lgif/cgifcontext.cpp +++ b/core/fxcodec/lgif/cgifcontext.cpp @@ -17,7 +17,7 @@ CGifContext::CGifContext(CCodec_GifModule* gif_module, CCodec_GifModule::Delegate* pDelegate) : m_pModule(gif_module), m_pDelegate(pDelegate), - global_pal_num(0), + global_pal_exp(0), img_row_offset(0), img_row_avail_size(0), avail_in(0), diff --git a/core/fxcodec/lgif/cgifcontext.h b/core/fxcodec/lgif/cgifcontext.h index d85243711d..71cf2bc75e 100644 --- a/core/fxcodec/lgif/cgifcontext.h +++ b/core/fxcodec/lgif/cgifcontext.h @@ -40,7 +40,7 @@ class CGifContext : public CCodec_GifModule::Context { UnownedPtr<CCodec_GifModule> m_pModule; UnownedPtr<CCodec_GifModule::Delegate> m_pDelegate; std::vector<GifPalette> m_GlobalPalette; - int32_t global_pal_num; + uint8_t global_pal_exp; uint32_t img_row_offset; uint32_t img_row_avail_size; uint32_t avail_in; diff --git a/core/fxcodec/lgif/fx_gif.cpp b/core/fxcodec/lgif/fx_gif.cpp index 18385c3bdd..ea78259420 100644 --- a/core/fxcodec/lgif/fx_gif.cpp +++ b/core/fxcodec/lgif/fx_gif.cpp @@ -147,6 +147,7 @@ GifDecodeStatus gif_decode_image_info(CGifContext* context) { } GifLF* gif_img_info_lf_ptr = (GifLF*)&gif_img_info_ptr->local_flag; if (gif_img_info_lf_ptr->local_pal) { + gif_image->local_pallette_exp = gif_img_info_lf_ptr->pal_bits; int32_t loc_pal_size = (2 << gif_img_info_lf_ptr->pal_bits) * 3; uint8_t* loc_pal_ptr = nullptr; if (!gif_read_data(context, &loc_pal_ptr, loc_pal_size)) { @@ -162,7 +163,7 @@ GifDecodeStatus gif_decode_image_info(CGifContext* context) { context->skip_size = skip_size_org; return GifDecodeStatus::Unfinished; } - gif_image->image_code_size = *code_size_ptr; + gif_image->image_code_exp = *code_size_ptr; context->RecordCurrentPosition(&gif_image->image_data_pos); gif_image->image_data_pos += context->skip_size; gif_image->m_ImageGCE = nullptr; @@ -214,10 +215,13 @@ CGifLZWDecoder::CGifLZWDecoder(char* error_ptr) CGifLZWDecoder::~CGifLZWDecoder() {} -void CGifLZWDecoder::InitTable(uint8_t code_len) { - code_size = code_len; - ASSERT(code_size < 13); - code_clear = 1 << code_size; +void CGifLZWDecoder::InitTable(uint8_t color_exp, uint8_t code_exp) { + // TODO(rharrison): Refactor all of this, so that initializing the table with + // bad values will kill the decompress. + ASSERT(code_exp <= GIF_MAX_LZW_EXP); + code_color_end = std::min(2 << color_exp, 1 << code_exp); + code_size = code_exp; + code_clear = 1 << code_exp; code_end = code_clear + 1; bits_left = 0; code_store = 0; @@ -247,6 +251,9 @@ bool CGifLZWDecoder::DecodeString(uint16_t code) { stack[GIF_MAX_LZW_CODE - 1 - stack_size++] = code_table[code].suffix; code = code_table[code].prefix; } + if (code >= code_color_end) + return false; + stack[GIF_MAX_LZW_CODE - 1 - stack_size++] = static_cast<uint8_t>(code); code_first = static_cast<uint8_t>(code); return true; @@ -282,7 +289,7 @@ GifDecodeStatus CGifLZWDecoder::Decode(uint8_t* des_buf, uint32_t* des_size) { } ASSERT(err_msg_ptr); while (i <= *des_size && (avail_in > 0 || bits_left >= code_size_cur)) { - if (code_size_cur > 12) { + if (code_size_cur > GIF_MAX_LZW_EXP) { strncpy(err_msg_ptr, "Code Length Out Of Range", GIF_MAX_ERROR_SIZE - 1); return GifDecodeStatus::Error; } @@ -383,9 +390,9 @@ GifDecodeStatus gif_read_header(CGifContext* context) { return GifDecodeStatus::Unfinished; } if (reinterpret_cast<GifGF*>(&gif_lsd_ptr->global_flag)->global_pal) { - context->global_pal_num = - 2 << reinterpret_cast<GifGF*>(&gif_lsd_ptr->global_flag)->pal_bits; - int32_t global_pal_size = context->global_pal_num * 3; + context->global_pal_exp = + reinterpret_cast<GifGF*>(&gif_lsd_ptr->global_flag)->pal_bits; + int32_t global_pal_size = (2 << context->global_pal_exp) * 3; uint8_t* global_pal_ptr = nullptr; if (!gif_read_data(context, &global_pal_ptr, global_pal_size)) { context->skip_size = skip_size_org; @@ -558,7 +565,7 @@ GifDecodeStatus gif_load_frame(CGifContext* context, int32_t frame_num) { return GifDecodeStatus::Error; } } - if (gif_image_ptr->image_code_size >= 13) { + if (gif_image_ptr->image_code_exp > GIF_MAX_LZW_EXP) { gif_image_ptr->m_ImageRowBuf.clear(); context->AddError("Error Invalid Code Size"); return GifDecodeStatus::Error; @@ -566,7 +573,10 @@ GifDecodeStatus gif_load_frame(CGifContext* context, int32_t frame_num) { if (!context->m_ImgDecoder.get()) context->m_ImgDecoder = pdfium::MakeUnique<CGifLZWDecoder>(context->m_szLastError); - context->m_ImgDecoder->InitTable(gif_image_ptr->image_code_size); + context->m_ImgDecoder->InitTable(!gif_image_ptr->m_LocalPalettes.empty() + ? gif_image_ptr->local_pallette_exp + : context->global_pal_exp, + gif_image_ptr->image_code_exp); context->img_row_offset = 0; context->img_row_avail_size = 0; context->img_pass_num = 0; diff --git a/core/fxcodec/lgif/fx_gif.h b/core/fxcodec/lgif/fx_gif.h index fd95aba17a..bddb22b30c 100644 --- a/core/fxcodec/lgif/fx_gif.h +++ b/core/fxcodec/lgif/fx_gif.h @@ -21,6 +21,7 @@ class CGifContext; #define GIF_BLOCK_CE 0xFE #define GIF_BLOCK_AE 0xFF #define GIF_BLOCK_TERMINAL 0x00 +#define GIF_MAX_LZW_EXP 12 #define GIF_MAX_LZW_CODE 4096 #define GIF_DATA_BLOCK 255 #define GIF_MAX_ERROR_SIZE 256 @@ -116,7 +117,8 @@ class GifImage { std::vector<GifPalette> m_LocalPalettes; std::vector<uint8_t> m_ImageRowBuf; GifImageInfo m_ImageInfo; - uint8_t image_code_size; + uint8_t local_pallette_exp; + uint8_t image_code_exp; uint32_t image_data_pos; int32_t image_row_num; }; @@ -131,7 +133,7 @@ class CGifLZWDecoder { explicit CGifLZWDecoder(char* error_ptr); ~CGifLZWDecoder(); - void InitTable(uint8_t code_len); + void InitTable(uint8_t color_exp, uint8_t code_exp); GifDecodeStatus Decode(uint8_t* des_buf, uint32_t* des_size); void Input(uint8_t* src_buf, uint32_t src_size); uint32_t GetAvailInput(); @@ -143,6 +145,7 @@ class CGifLZWDecoder { uint8_t code_size; uint8_t code_size_cur; + uint16_t code_color_end; uint16_t code_clear; uint16_t code_end; uint16_t code_next; diff --git a/testing/libfuzzer/xfa_codec_fuzzer.h b/testing/libfuzzer/xfa_codec_fuzzer.h index 0d6b43e7b8..5193a8930f 100644 --- a/testing/libfuzzer/xfa_codec_fuzzer.h +++ b/testing/libfuzzer/xfa_codec_fuzzer.h @@ -37,7 +37,7 @@ class XFACodecFuzzer { bitmap->Create(decoder->GetWidth(), decoder->GetHeight(), FXDIB_Argb); int32_t frames; - if (decoder->GetFrames(frames) != FXCODEC_STATUS_DECODE_READY || + if (decoder->GetFrames(&frames) != FXCODEC_STATUS_DECODE_READY || frames == 0) { return 0; } diff --git a/xfa/fxfa/cxfa_ffimage.cpp b/xfa/fxfa/cxfa_ffimage.cpp index 757867f076..9903e6b25d 100644 --- a/xfa/fxfa/cxfa_ffimage.cpp +++ b/xfa/fxfa/cxfa_ffimage.cpp @@ -26,8 +26,7 @@ bool CXFA_FFImage::LoadWidget() { if (GetDataAcc()->GetImageImage()) return true; - GetDataAcc()->LoadImageImage(); - return CXFA_FFDraw::LoadWidget(); + return GetDataAcc()->LoadImageImage() ? CXFA_FFDraw::LoadWidget() : false; } void CXFA_FFImage::UnloadWidget() { diff --git a/xfa/fxfa/cxfa_ffpageview.cpp b/xfa/fxfa/cxfa_ffpageview.cpp index 1de900c2f7..0e0db8dae0 100644 --- a/xfa/fxfa/cxfa_ffpageview.cpp +++ b/xfa/fxfa/cxfa_ffpageview.cpp @@ -208,7 +208,8 @@ CXFA_FFWidget* CXFA_FFPageWidgetIterator::GetWidget( if (!pWidget->IsLoaded() && !!(pWidget->GetStatus() & XFA_WidgetStatus_Visible)) { - pWidget->LoadWidget(); + if (!pWidget->LoadWidget()) + return nullptr; } return pWidget; } diff --git a/xfa/fxfa/cxfa_ffwidget.cpp b/xfa/fxfa/cxfa_ffwidget.cpp index 7763a19972..859287388f 100644 --- a/xfa/fxfa/cxfa_ffwidget.cpp +++ b/xfa/fxfa/cxfa_ffwidget.cpp @@ -899,6 +899,17 @@ void XFA_DrawBox(CXFA_Box box, XFA_BOX_Stroke(box, strokes, pGS, rtWidget, matrix, dwFlags); } +bool IsFXCodecErrorStatus(FXCODEC_STATUS status) { + return (status == FXCODEC_STATUS_ERROR || +#ifdef PDF_ENABLE_XFA + status == FXCODEC_STATUS_ERR_MEMORY || +#endif // PDF_ENABLE_XFA + status == FXCODEC_STATUS_ERR_READ || + status == FXCODEC_STATUS_ERR_FLUSH || + status == FXCODEC_STATUS_ERR_FORMAT || + status == FXCODEC_STATUS_ERR_PARAMS); +} + } // namespace CXFA_FFWidget::CXFA_FFWidget(CXFA_WidgetAcc* pDataAcc) @@ -2001,14 +2012,29 @@ RetainPtr<CFX_DIBitmap> XFA_LoadImageFromBuffer( pBitmap->Create(pProgressiveDecoder->GetWidth(), pProgressiveDecoder->GetHeight(), dibFormat); pBitmap->Clear(0xffffffff); + int32_t nFrames; - if ((pProgressiveDecoder->GetFrames(nFrames) == - FXCODEC_STATUS_DECODE_READY) && - (nFrames > 0)) { - pProgressiveDecoder->StartDecode(pBitmap, 0, 0, pBitmap->GetWidth(), - pBitmap->GetHeight()); - pProgressiveDecoder->ContinueDecode(); + if (pProgressiveDecoder->GetFrames(&nFrames) != FXCODEC_STATUS_DECODE_READY || + nFrames <= 0) { + pBitmap = nullptr; + return pBitmap; + } + + FXCODEC_STATUS status = pProgressiveDecoder->StartDecode( + pBitmap, 0, 0, pBitmap->GetWidth(), pBitmap->GetHeight()); + if (IsFXCodecErrorStatus(status)) { + pBitmap = nullptr; + return pBitmap; } + + while (status == FXCODEC_STATUS_DECODE_TOBECONTINUE) { + status = pProgressiveDecoder->ContinueDecode(); + if (IsFXCodecErrorStatus(status)) { + pBitmap = nullptr; + return pBitmap; + } + } + return pBitmap; } |