New issue
Advanced search Search tips

Issue 614691 link

Starred by 3 users

Issue metadata

Status: Fixed
Owner:
Closed: Aug 1
Cc:
Components:
EstimatedDays: ----
NextAction: ----
OS: Windows
Pri: 2
Type: Bug



Sign in to add a comment

PDFium: Memory leak in opj_j2k_merge_ppt function due to optimized assert

Reported by stackexp...@gmail.com, May 25 2016

Issue description

VULNERABILITY DETAILS
Memory leak can be happened in Release version of pdfium under Windows. In function opj_j2k_merge_ppt, the assert preconditions will be skipped when compiled with Release mode. In this scenario, memory leak happens when p_tcp->ppt_buffer is not NULL. The following code and comments demonstrate this condition.

3804 static OPJ_BOOL opj_j2k_merge_ppt(opj_tcp_t *p_tcp, opj_event_mgr_t * p_manager)
3805 {
3806    OPJ_UINT32 i, l_ppt_data_size;
3807    /* preconditions */
3808    assert(p_tcp != 00);
3809    assert(p_manager != 00);
3810    assert(p_tcp->ppt_buffer == NULL);   // SKIPPED IN RELEASE VERSION!!!
38XX    
38XX    if (p_tcp->ppt == 0U) {
38XX        return OPJ_TRUE;
38XX    }
38XX    
38XX    l_ppt_data_size = 0U;
38XX    for (i = 0U; i < p_tcp->ppt_markers_count; ++i) {
38XX        l_ppt_data_size += p_tcp->ppt_markers[i].m_data_size;
38XX    }
38XX    
38XX    p_tcp->ppt_buffer = (OPJ_BYTE *) opj_malloc(l_ppt_data_size);   // MEMORY LEAK!!!
38XX    if (p_tcp->ppt_buffer == 00) {
38XX        opj_event_msg(p_manager, EVT_ERROR, "Not enough memory to read PPT marker\n");
38XX        return OPJ_FALSE;
38XX    }

DEBUG INFORMATION
Memory leak happens when entering function opj_j2k_merge_ppt the second time.
0:000> bp pdfium_test!opj_j2k_merge_ppt
0:000> g
$$ first time break
Breakpoint 0 hit
eax=092b0c00 ebx=09125fb8 ecx=0cd8ec8c edx=00000146 esi=092a4f28 edi=092a2fd4
eip=01135fb0 esp=0037d1f4 ebp=0037d218 iopl=0         nv up ei pl nz na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000206
pdfium_test!opj_j2k_merge_ppt:
01135fb0 55              push    ebp

0:000> g
$$ second time break
Breakpoint 0 hit
eax=092b0c00 ebx=09125fb8 ecx=00000154 edx=00000000 esi=092a4f28 edi=092a2fd4
eip=01135fb0 esp=0037d1f4 ebp=0037d218 iopl=0         nv up ei pl nz na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000206
pdfium_test!opj_j2k_merge_ppt:
01135fb0 55              push    ebp

$$ p_tcp->ppt_buffer was not NULL!
0:000> dt p_tcp
Local var @ 0x37d1f8 Type opj_tcp*
0x092b0c00 
   +0x000 csty             : 1
   +0x004 prg              : 0 ( OPJ_LRCP )
   +0x008 numlayers        : 3
   +0x00c num_layers_to_decode : 3
   +0x010 mct              : 0
   +0x014 rates            : [100] 0 
   +0x1a4 numpocs          : 0
   +0x1a8 pocs             : [32] opj_poc
   +0x1428 ppt_markers_count : 0
   +0x142c ppt_markers      : (null) 
   +0x1430 ppt_data         : 0x09722ff9  "???"
   +0x1434 ppt_buffer       : 0x09722fe8  "@@HHPHHPHHPHHPHHP???"  -> NOT NULL!!!!
   +0x1438 ppt_data_size    : 0x11
   +0x143c ppt_len          : 0
   +0x1440 distoratio       : [100] 0 
   +0x15d0 tccps            : 0x09368358 opj_tccp
   +0x15d4 m_nb_tile_parts  : 1
   +0x15d8 m_data           : (null) 
   +0x15dc m_data_size      : 0
   +0x15e0 mct_norms        : (null) 
   +0x15e4 m_mct_decoding_matrix : (null) 
   +0x15e8 m_mct_coding_matrix : (null) 
   +0x15ec m_mct_records    : 0x093fcf38 opj_mct_data
   +0x15f0 m_nb_mct_records : 0
   +0x15f4 m_nb_max_mct_records : 0
   +0x15f8 m_mcc_records    : 0x093fef38 opj_simple_mcc_decorrelation_data
   +0x15fc m_nb_mcc_records : 0
   +0x1600 m_nb_max_mcc_records : 0xa
   +0x1604 cod              : 0y0
   +0x1604 ppt              : 0y1
   +0x1604 POC              : 0y0

$$ malloc stack trace
0:000> !heap -p -a 0x09722fe8
    address 09722fe8 found in
    _DPH_HEAP_ROOT @ f1000
    in busy allocation (  DPH_HEAP_BLOCK:  UserAddr  UserSize - VirtAddr  VirtSize)
                                 96b1820:   9722fe8        11 -  9722000      2000
    10b58e89 verifier!AVrfDebugPageHeapAllocate+0x00000229
    77621d4e ntdll!RtlDebugAllocateHeap+0x00000030
    775db586 ntdll!RtlpAllocateHeap+0x000000c4
    77583541 ntdll!RtlAllocateHeap+0x0000023a
    01352f38 pdfium_test!_malloc_base+0x00000038 [d:\th\minkernel\crts\ucrt\src\appcrt\heap\malloc_base.cpp @ 29]
    01135ffc pdfium_test!opj_j2k_merge_ppt+0x0000004c [third_party\libopenjpeg20\j2k.c @ 3821]
    0113756a pdfium_test!opj_j2k_read_tile_header+0x0000053a [third_party\libopenjpeg20\j2k.c @ 8015]
    0113514a pdfium_test!opj_j2k_decode_tiles+0x0000007a [third_party\libopenjpeg20\j2k.c @ 9578]
    01139b26 pdfium_test!opj_jp2_exec+0x00000036 [third_party\libopenjpeg20\jp2.c @ 2246]
    01134c00 pdfium_test!opj_j2k_decode+0x00000050 [third_party\libopenjpeg20\j2k.c @ 9806]
    011314f7 pdfium_test!opj_decode+0x00000027 [third_party\libopenjpeg20\openjpeg.c @ 412]
    010e951f pdfium_test!CJPX_Decoder::Init+0x0000017f [core\fxcodec\codec\fx_codec_jpx_opj.cpp @ 764]
    010e8ee0 pdfium_test!CCodec_JpxModule::CreateDecoder+0x00000040 [core\fxcodec\codec\fx_codec_jpx_opj.cpp @ 887]
    010d7b37 pdfium_test!CPDF_DIBSource::LoadJpxBitmap+0x00000067 [core\fpdfapi\fpdf_render\fpdf_render_loadimage.cpp @ 636]
    010d6231 pdfium_test!CPDF_DIBSource::CreateDecoder+0x00000241 [core\fpdfapi\fpdf_render\fpdf_render_loadimage.cpp @ 593]
    010d876d pdfium_test!CPDF_DIBSource::StartLoadDIBSource+0x0000017d [core\fpdfapi\fpdf_render\fpdf_render_loadimage.cpp @ 311]
    010b4b67 pdfium_test!CPDF_ImageCacheEntry::StartGetCachedBitmap+0x00000067 [core\fpdfapi\fpdf_render\fpdf_render_cache.cpp @ 277]
    010b4c6f pdfium_test!CPDF_PageRenderCache::StartGetCachedBitmap+0x000000cf [core\fpdfapi\fpdf_render\fpdf_render_cache.cpp @ 124]
    010d8554 pdfium_test!CPDF_ImageLoaderHandle::Start+0x00000044 [core\fpdfapi\fpdf_render\fpdf_render_loadimage.cpp @ 1504]
    010d84fd pdfium_test!CPDF_ImageLoader::Start+0x0000005d [core\fpdfapi\fpdf_render\fpdf_render_loadimage.cpp @ 1565]
    010bad30 pdfium_test!CPDF_ImageRenderer::StartLoadDIBSource+0x00000070 [core\fpdfapi\fpdf_render\fpdf_render_image.cpp @ 342]
    010ba7b4 pdfium_test!CPDF_ImageRenderer::Start+0x00000074 [core\fpdfapi\fpdf_render\fpdf_render_image.cpp @ 486]
    0109c463 pdfium_test!CPDF_RenderStatus::ContinueSingleObject+0x000000c3 [core\fpdfapi\fpdf_render\fpdf_render.cpp @ 288]
    0109c272 pdfium_test!CPDF_ProgressiveRenderer::Continue+0x000002f2 [core\fpdfapi\fpdf_render\fpdf_render.cpp @ 1057]
    0106a3d1 pdfium_test!FPDF_RenderPage_Retail+0x00000221 [fpdfsdk\fpdfview.cpp @ 918]
    0106aca9 pdfium_test!FPDF_RenderPageBitmap+0x00000099 [fpdfsdk\fpdfview.cpp @ 654]
    010631e2 pdfium_test!RenderPage+0x000001d2 [samples\pdfium_test.cc @ 519]
    010635b8 pdfium_test!RenderPdf+0x000002b8 [samples\pdfium_test.cc @ 694]
    010694fe pdfium_test!main+0x0000042e [samples\pdfium_test.cc @ 975]
    01336696 pdfium_test!__scrt_common_main_seh+0x000000ff [f:\dd\vctools\crt\vcstartup\src\startup\exe_common.inl @ 264]
    7528338a kernel32!BaseThreadInitThunk+0x0000000e

VERSION
Chrome Version: [x.x.x.x] + [stable, beta, or dev]
Operating System: Windows 7

REPRODUCTION CASE
See attachments.

The problem does not exist under Linux because assert was not optimized by default. But this is a common problem under Windows. Please consider replace all assert macros in the openjpeg library. Although this may be not a security issue in this particular condition, the assert macro may cause security problems in other conditions because there are lots of assert in this library.

CREDIT
This issue was discovered by Ke Liu of Tencent's Xuanwu LAB.


 
memory_leak.pdf
1.3 KB Download
memory_leak.j2k
340 bytes Download
To demonstrate the severity of this problem, let's have a look at the division-by-zero issue related with the assert macro.

In file opj_intmath.h, there are two functions use assert to check conditions. However, it can cause division-by-zero problems if the value of variable b is zero.

/**
Divide an integer and round upwards
@return Returns a divided by b
*/
static INLINE OPJ_INT32 opj_int_ceildiv(OPJ_INT32 a, OPJ_INT32 b) {
	assert(b);
	return (a + b - 1) / b;
}
/**
Divide an integer and round upwards
@return Returns a divided by b
*/
static INLINE OPJ_UINT32  opj_uint_ceildiv(OPJ_UINT32  a, OPJ_UINT32  b) {
	assert(b);
	return (a + b - 1) / b;
}


I'll attach a proof-of-concept file tomorrow.
another security issue related to this topic:
https://bugs.chromium.org/p/chromium/issues/detail?id=613160

> [$3000][613160] High CVE-2016-1681: Heap overflow in PDFium. Credit to Aleksandar Nikolic of Cisco Talos.

Comment 3 Deleted

Division-By-Zero PoC
--------------------
(4854.354): Integer divide-by-zero - code c0000094 (!!! second chance !!!)
eax=ffffffff ebx=0000001f ecx=0998ae00 edx=ffffffff esi=09986f18 edi=00000002
eip=0137b45a esp=003dd278 ebp=003dd2ac iopl=0         nv up ei ng nz na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010286
pdfium_test!opj_int_ceildiv+0x1 [inlined in pdfium_test!opj_pi_next_pcrl+0x1fa]:
0137b45a f77d08          idiv    eax,dword ptr [ebp+8] ss:002b:003dd2b4=00000000

0:000> k
pdfium_test!opj_int_ceildiv+0x1 [third_party\libopenjpeg20\opj_intmath.h @ 121]
pdfium_test!opj_pi_next_pcrl+0x1fa [third_party\libopenjpeg20\pi.c @ 443]
pdfium_test!opj_t2_decode_packets+0x18a [third_party\libopenjpeg20\t2.c @ 447]
pdfium_test!opj_tcd_t2_decode+0x3d [third_party\libopenjpeg20\tcd.c @ 1558]
pdfium_test!opj_tcd_decode_tile+0x54 [third_party\libopenjpeg20\tcd.c @ 1297]
pdfium_test!opj_j2k_decode_tile+0x67 [third_party\libopenjpeg20\j2k.c @ 8069]
pdfium_test!opj_j2k_decode_tiles+0xcd [third_party\libopenjpeg20\j2k.c @ 9606]
pdfium_test!opj_jp2_exec+0x36 [third_party\libopenjpeg20\jp2.c @ 2246]
pdfium_test!opj_j2k_decode+0x50 [third_party\libopenjpeg20\j2k.c @ 9806]
pdfium_test!opj_jp2_decode+0x24 [third_party\libopenjpeg20\jp2.c @ 1487]
pdfium_test!opj_decode+0x27 [third_party\libopenjpeg20\openjpeg.c @ 412]
pdfium_test!CJPX_Decoder::Init+0x17f [core\fxcodec\codec\fx_codec_jpx_opj.cpp @ 764]
pdfium_test!CCodec_JpxModule::CreateDecoder+0x40 [core\fxcodec\codec\fx_codec_jpx_opj.cpp @ 887]
pdfium_test!CPDF_DIBSource::LoadJpxBitmap+0x67 [core\fpdfapi\fpdf_render\fpdf_render_loadimage.cpp @ 636]
pdfium_test!CPDF_DIBSource::CreateDecoder+0x241 [core\fpdfapi\fpdf_render\fpdf_render_loadimage.cpp @ 593]
pdfium_test!CPDF_DIBSource::StartLoadDIBSource+0x17d [core\fpdfapi\fpdf_render\fpdf_render_loadimage.cpp @ 311]
pdfium_test!CPDF_ImageCacheEntry::StartGetCachedBitmap+0x67 [core\fpdfapi\fpdf_render\fpdf_render_cache.cpp @ 277]
pdfium_test!CPDF_PageRenderCache::StartGetCachedBitmap+0xcf [core\fpdfapi\fpdf_render\fpdf_render_cache.cpp @ 124]
pdfium_test!CPDF_ImageLoaderHandle::Start+0x44 [core\fpdfapi\fpdf_render\fpdf_render_loadimage.cpp @ 1504]
pdfium_test!CPDF_ImageLoader::Start+0x5d [core\fpdfapi\fpdf_render\fpdf_render_loadimage.cpp @ 1565]
pdfium_test!CPDF_ImageRenderer::StartLoadDIBSource+0x70 [core\fpdfapi\fpdf_render\fpdf_render_image.cpp @ 342]
pdfium_test!CPDF_ImageRenderer::Start+0x74 [core\fpdfapi\fpdf_render\fpdf_render_image.cpp @ 486]
pdfium_test!CPDF_RenderStatus::ContinueSingleObject+0xc3 [core\fpdfapi\fpdf_render\fpdf_render.cpp @ 288]
pdfium_test!CPDF_ProgressiveRenderer::Continue+0x2f2 [core\fpdfapi\fpdf_render\fpdf_render.cpp @ 1057]
pdfium_test!FPDF_RenderPage_Retail+0x221 [fpdfsdk\fpdfview.cpp @ 918]
pdfium_test!FPDF_RenderPageBitmap+0x99 [fpdfsdk\fpdfview.cpp @ 654]
pdfium_test!RenderPage+0x1d2 [samples\pdfium_test.cc @ 519]
pdfium_test!RenderPdf+0x2b8 [samples\pdfium_test.cc @ 694]
pdfium_test!main+0x42e [samples\pdfium_test.cc @ 975]
pdfium_test!invoke_main+0x1d [f:\dd\vctools\crt\vcstartup\src\startup\exe_common.inl @ 74]
pdfium_test!__scrt_common_main_seh+0xff [f:\dd\vctools\crt\vcstartup\src\startup\exe_common.inl @ 264]
kernel32!BaseThreadInitThunk+0xe
ntdll!__RtlUserThreadStart+0x70
ntdll!_RtlUserThreadStart+0x1b


Source code
-----------
static INLINE OPJ_INT32 opj_int_ceildiv(OPJ_INT32 a, OPJ_INT32 b) {
	assert(b);  // <---------- check passed
	return (a + b - 1) / b;  // <----------- b == 0
}
division-by-zero.j2k
293 bytes Download
division-by-zero.pdf
1.3 KB Download
Oh no, I forgot to add 'PDFium' in the title. ochang@

Comment 6 by mea...@chromium.org, May 26 2016

Cc: och...@chromium.org
Labels: OS-Windows
Owner: tsepez@chromium.org
Status: Assigned (was: Unconfirmed)
Summary: Security: PDFium: Memory leak in opj_j2k_merge_ppt function due to optimized assert (was: Security: Memory leak in opj_j2k_merge_ppt function due to optimized assert)
Tom, can you please triage?

Comment 7 by och...@chromium.org, May 26 2016

Components: Internals>Plugins>PDF
Labels: -Type-Bug-Security -Restrict-View-SecurityTeam Type-Bug
Summary: PDFium: Memory leak in opj_j2k_merge_ppt function due to optimized assert (was: Security: PDFium: Memory leak in opj_j2k_merge_ppt function due to optimized assert)
Thanks for the report.

Memory leaks and floating point exceptions aren't considered to be security vulnerabilities.

While there has been a past pattern of asserts that would've prevented security issues, there isn't any vulnerability demonstrated here -- flipping labels.
OK. But I still think use assert to check conditions under Windows is a bad idea.
I'll open a security issue if I'm lucky enough to find a vulnerability. :)

Comment 9 by f...@chromium.org, Jun 6 2016

ochang@, can you take a look at this again in light of https://bugs.chromium.org/p/chromium/issues/detail?id=616686?
re https://bugs.chromium.org/p/chromium/issues/detail?id=616686#c11:

stackexploit, I missed your point about Linux release builds including asserts while Windows doesn't -- this shouldn't be the case. How are you building pdfium on Linux? Asserts should be disabled in release builds regardless of platform. 

Enabling all asserts for release builds is not feasible, nor the right way to fix any security vulnerabilities. The asserts you've pointed out are all in third party libraries, where a big chunk of these asserts are almost certainly bad/wrong.
Hi ochang@, thanks for commenting.

For one thing, asserts are definitely disabled in pdfium's release builds regardless of platform. Sorry for my wrong descriptions.

For another, I couldn't agree more with what you said. The assert macro is widely used in these third party libraries. What I want to say is that these asserts may lead to security risks.



 

Owner: dsinclair@chromium.org
Dan, for routing this issue. I'm not going to be looking at this.  Thanks.
What are the steps in order to repro this leak? Does it happen under msan builds?
I just debugged it. The assert check will be failed in debug mode because p_tcp->ppt_buffer hold a heap buffer here.

3810    assert(p_tcp->ppt_buffer == NULL);   // SKIPPED IN RELEASE VERSION!!!
38XX    p_tcp->ppt_buffer = (OPJ_BYTE *) opj_malloc(l_ppt_data_size);   // MEMORY LEAK!!!
I've uploaded a patch for this issue which is available at https://codereview.chromium.org/2353463002
I'm not sure what you mean by debugged it, is there a pdf that fails with this assert enabled? Is there some way we can reproduce the issue in order to verify that it is fixed?
Yes of course. I've uploaded a pdf file in the original post. Please download the memory_leak.pdf file to reproduce it.
Cc: dsinclair@chromium.org
Labels: Pri-2
Owner: thestig@chromium.org
Too bad nobody forwarded this upstream. FYI, openjpeg finally fixed this recently. It's effectively https://codereview.chromium.org/2353463002

We'll patch it in.

https://github.com/uclouvain/openjpeg/commit/0c913b0aba409148b51ca43d45c50ae595449723

There was a previous attempt to fix it in a different way, but that got reverted.
https://github.com/uclouvain/openjpeg/commit/9906fbf737692486cebabe98169988d818e2e66a
https://github.com/uclouvain/openjpeg/commit/832dfd18665da08745748bde2d2563f00c7cd9e7
Status: Fixed (was: Assigned)
Project Member

Comment 21 by bugdroid1@chromium.org, Aug 1

The following revision refers to this bug:
  https://chromium.googlesource.com/chromium/src.git/+/e1cecd2f6b0dbafadae7529e413b6d1c66d57f92

commit e1cecd2f6b0dbafadae7529e413b6d1c66d57f92
Author: pdfium-chromium-autoroll <pdfium-chromium-autoroll@skia-buildbots.google.com.iam.gserviceaccount.com>
Date: Wed Aug 01 20:48:23 2018

Roll src/third_party/pdfium ad39141331e5..2563fc3895f2 (5 commits)

https://pdfium.googlesource.com/pdfium.git/+log/ad39141331e5..2563fc3895f2


git log ad39141331e5..2563fc3895f2 --date=short --no-merges --format='%ad %ae %s'
2018-08-01 tsepez@chromium.org Make FPDF_FormHandle be represented as an incomplete type.
2018-08-01 thestig@chromium.org Encapsulate some public static methods in CFXJSE_FormCalcContext.
2018-08-01 thestig@chromium.org Fix assertion in opj_j2k_merge_ppt().
2018-08-01 thestig@chromium.org Refactor PatternStringType().
2018-08-01 thestig@chromium.org Roll third_party/freetype/src/ b532d7ce7..578bcf103 (28 commits)


Created with:
  gclient setdep -r src/third_party/pdfium@2563fc3895f2

The AutoRoll server is located here: https://pdfium-roll.skia.org

Documentation for the AutoRoller is here:
https://skia.googlesource.com/buildbot/+/master/autoroll/README.md

If the roll is causing failures, please contact the current sheriff, who should
be CC'd on the roll, and stop the roller if necessary.



BUG= chromium:614691 
TBR=dsinclair@chromium.org

Change-Id: Ia0d452e71ddb24a981209c38b55c480b94d7b0e1
Reviewed-on: https://chromium-review.googlesource.com/1159024
Reviewed-by: pdfium-chromium-autoroll <pdfium-chromium-autoroll@skia-buildbots.google.com.iam.gserviceaccount.com>
Commit-Queue: pdfium-chromium-autoroll <pdfium-chromium-autoroll@skia-buildbots.google.com.iam.gserviceaccount.com>
Cr-Commit-Position: refs/heads/master@{#579928}
[modify] https://crrev.com/e1cecd2f6b0dbafadae7529e413b6d1c66d57f92/DEPS

Sign in to add a comment