Security: Out-Of-Bounds Write in RunLengthDecode
Reported by
zhouzhen...@gmail.com,
Sep 26
|
|||||||||||||||||
Issue description
VULNERABILITY DETAILS
This issue was found by fuzzing against a 64-bit asan linux build of pdfium_test.
RunLengthDecode in fpdf_parser_decode.cpp:
-----------------------------------
size_t i = 0;
*dest_size = 0;
while (i < src_span.size()) {
if (src_span[i] == 128)
break;
uint32_t old = *dest_size;
if (src_span[i] < 128) {
*dest_size += src_span[i] + 1;
if (*dest_size < old)
return FX_INVALID_OFFSET;
i += src_span[i] + 2;
} else {
*dest_size += 257 - src_span[i];
if (*dest_size < old)
return FX_INVALID_OFFSET;
i += 2;
}
}
-------------------------------------
run the poc, the dest_size is 2623, then do some alloc, copy buffer
-------------------------------------
*dest_buf = FX_Alloc(uint8_t, *dest_size);
i = 0;
int dest_count = 0;
while (i < src_span.size()) {
if (src_span[i] == 128)
break;
if (src_span[i] < 128) {
uint32_t copy_len = src_span[i] + 1;
uint32_t buf_left = src_span.size() - i - 1;
if (buf_left < copy_len) {
uint32_t delta = copy_len - buf_left;
copy_len = buf_left;
memset(*dest_buf + dest_count + copy_len, '\0', delta);
}
memcpy(*dest_buf + dest_count, &src_span[i + 1], copy_len); // <--- out of bounds write here. copy_len is larger than 2623 - dest_count
dest_count += src_span[i] + 1;
i += src_span[i] + 2;
} else {
int fill = 0;
if (i < src_span.size() - 1)
fill = src_span[i + 1];
memset(*dest_buf + dest_count, fill, 257 - src_span[i]);
dest_count += 257 - src_span[i];
i += 2;
}
}
------------------------------
VERSION
Chrome Version: asan-linux-beta-70.0.3538.16
Operating System: Fedora 28 x86_64
REPRODUCTION CASE
./pdfium_test tests_6376f0dfe1b3796a5e5d31958269ac01152cc567
Rendering PDF file tests_6376f0dfe1b3796a5e5d31958269ac01152cc567.
AddressSanitizer:DEADLYSIGNAL
=================================================================
==22091==ERROR: AddressSanitizer: ABRT on unknown address 0x03e80000564b (pc 0x7f96c3a8ceab bp 0x7fff16942c30 sp 0x7fff16942990 T0)
SCARINESS: 10 (signal)
#0 0x7f96c3a8ceaa in __GI_raise (/lib64/libc.so.6+0x36eaa)
#1 0x7f96c3a775b8 in __GI_abort (/lib64/libc.so.6+0x215b8)
#2 0x2c35479 in RunLengthDecode(pdfium::span<unsigned char const>, unsigned char**, unsigned int*) third_party/pdfium/core/fpdfapi/parser/fpdf_parser_decode.cpp
#3 0x2ba1446 in DecodeInlineStream third_party/pdfium/core/fpdfapi/page/cpdf_streamparser.cpp:95:12
#4 0x2ba1446 in CPDF_StreamParser::ReadInlineStream(CPDF_Document*, std::__1::unique_ptr<CPDF_Dictionary, std::__1::default_delete<CPDF_Dictionary> >, CPDF_Object const*) third_party/pdfium/core/fpdfapi/page/cpdf_streamparser.cpp:186
#5 0x2b77dab in CPDF_StreamContentParser::Handle_BeginImage() third_party/pdfium/core/fpdfapi/page/cpdf_streamcontentparser.cpp:671:18
#6 0x2b94bb9 in CPDF_StreamContentParser::Parse(unsigned char const*, unsigned int, unsigned int, std::__1::vector<unsigned int, std::__1::allocator<unsigned int> > const&) third_party/pdfium/core/fpdfapi/page/cpdf_streamcontentparser.cpp:1536:9
#7 0x2b4599d in CPDF_ContentParser::Parse() third_party/pdfium/core/fpdfapi/page/cpdf_contentparser.cpp:211:33
#8 0x2b4463a in CPDF_ContentParser::Continue(PauseIndicatorIface*) third_party/pdfium/core/fpdfapi/page/cpdf_contentparser.cpp:133:22
#9 0x2b5b328 in CPDF_PageObjectHolder::ContinueParse(PauseIndicatorIface*) third_party/pdfium/core/fpdfapi/page/cpdf_pageobjectholder.cpp:59:18
#10 0x2b59048 in CPDF_Page::ParseContent() third_party/pdfium/core/fpdfapi/page/cpdf_page.cpp:110:3
#11 0x291868b in FPDF_LoadPage third_party/pdfium/fpdfsdk/fpdf_view.cpp:351:10
#12 0xb97407 in (anonymous namespace)::GetPageForIndex(_FPDF_FORMFILLINFO*, fpdf_document_t__*, int) third_party/pdfium/samples/pdfium_test.cc:502:23
#13 0xb91350 in RenderPage third_party/pdfium/samples/pdfium_test.cc:530:20
#14 0xb91350 in RenderPdf third_party/pdfium/samples/pdfium_test.cc:773
#15 0xb91350 in main third_party/pdfium/samples/pdfium_test.cc:948
#16 0x7f96c3a7911a in __libc_start_main (/lib64/libc.so.6+0x2311a)
#17 0xab5029 in _start (/home/henices/research/asan-linux-beta-70.0.3538.16/pdfium_test+0xab5029)
AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: ABRT (/lib64/libc.so.6+0x36eaa) in __GI_raise
==22091==ABORTING
testcase is in the attachment.
,
Sep 26
it reproduced on beta (m70), but didn't reproduce on stable (m69)
,
Sep 26
try to minimize the testcase.
~/research/asan-linux-beta-70.0.3538.16/pdfium_test ./min.pdf
Rendering PDF file ./min.pdf.
AddressSanitizer:DEADLYSIGNAL
=================================================================
==17134==ERROR: AddressSanitizer: ABRT on unknown address 0x03e8000042ee (pc 0x7f5c35f80eab bp 0x7fff0011ea90 sp 0x7fff0011e7f0 T0)
SCARINESS: 10 (signal)
#0 0x7f5c35f80eaa in __GI_raise (/lib64/libc.so.6+0x36eaa)
#1 0x7f5c35f6b5b8 in __GI_abort (/lib64/libc.so.6+0x215b8)
#2 0x2c35479 in RunLengthDecode(pdfium::span<unsigned char const>, unsigned char**, unsigned int*) third_party/pdfium/core/fpdfapi/parser/fpdf_parser_decode.cpp
#3 0x2ba1446 in DecodeInlineStream third_party/pdfium/core/fpdfapi/page/cpdf_streamparser.cpp:95:12
#4 0x2ba1446 in CPDF_StreamParser::ReadInlineStream(CPDF_Document*, std::__1::unique_ptr<CPDF_Dictionary, std::__1::default_delete<CPDF_Dictionary> >, CPDF_Object const*) third_party/pdf
ium/core/fpdfapi/page/cpdf_streamparser.cpp:186
#5 0x2b77dab in CPDF_StreamContentParser::Handle_BeginImage() third_party/pdfium/core/fpdfapi/page/cpdf_streamcontentparser.cpp:671:18
#6 0x2b94bb9 in CPDF_StreamContentParser::Parse(unsigned char const*, unsigned int, unsigned int, std::__1::vector<unsigned int, std::__1::allocator<unsigned int> > const&) third_party/p
dfium/core/fpdfapi/page/cpdf_streamcontentparser.cpp:1536:9
#7 0x2b4599d in CPDF_ContentParser::Parse() third_party/pdfium/core/fpdfapi/page/cpdf_contentparser.cpp:211:33
#8 0x2b4463a in CPDF_ContentParser::Continue(PauseIndicatorIface*) third_party/pdfium/core/fpdfapi/page/cpdf_contentparser.cpp:133:22
#9 0x2b5b328 in CPDF_PageObjectHolder::ContinueParse(PauseIndicatorIface*) third_party/pdfium/core/fpdfapi/page/cpdf_pageobjectholder.cpp:59:18
#10 0x2b59048 in CPDF_Page::ParseContent() third_party/pdfium/core/fpdfapi/page/cpdf_page.cpp:110:3
#11 0x291868b in FPDF_LoadPage third_party/pdfium/fpdfsdk/fpdf_view.cpp:351:10
#12 0xb97407 in (anonymous namespace)::GetPageForIndex(_FPDF_FORMFILLINFO*, fpdf_document_t__*, int) third_party/pdfium/samples/pdfium_test.cc:502:23
#13 0xb91350 in RenderPage third_party/pdfium/samples/pdfium_test.cc:530:20
#14 0xb91350 in RenderPdf third_party/pdfium/samples/pdfium_test.cc:773
#15 0xb91350 in main third_party/pdfium/samples/pdfium_test.cc:948
#16 0x7f5c35f6d11a in __libc_start_main (/lib64/libc.so.6+0x2311a)
#17 0xab5029 in _start (/home/henices/research/asan-linux-beta-70.0.3538.16/pdfium_test+0xab5029)
AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: ABRT (/lib64/libc.so.6+0x36eaa) in __GI_raise
==17134==ABORTING
,
Sep 26
,
Sep 26
,
Sep 26
This is a serious security regression. If you are not able to fix this quickly, please revert the change that introduced it. If this doesn't affect a release branch, or has not been properly classified for severity, please update the Security_Impact or Security_Severity labels, and remove the ReleaseBlock label. To disable this altogether, apply ReleaseBlock-NA. For more details visit https://www.chromium.org/issue-tracking/autotriage - Your friendly Sheriffbot
,
Sep 26
This issue is present on the M70 branch, but PDFium's current HEAD works fine.
,
Sep 26
https://pdfium-review.googlesource.com/41930 fixed it, so this is likely a duplicate of bug 879910 . We probably should merge the fix to the M70 branch. Also, I'm not sure there is an OOB write here. ASAN hit a SIGABRT, and did not print out the usual memory map to show where the bad write is. It's actually an out of bound read on |src_span|, but because it is a pdfium::base::span and not a raw array, span's operator[] ensures the OOB access does not happen.
,
Sep 26
,
Sep 26
compared to bug 879910 , back trace is slightly different. I'm also confused why ASAN is hit a SIGABRT, so i used gdb to debug. When debugging i found OOB write in memcpy ( comment #1 ), but it didn't crash immediately. Because I didn't minimize the testcase at that time, too many next was needed, so I submitted it first. This issue can cause OOB write many times, ASAN report code might not work correctly. If I have time i will look into it.
,
Sep 26
As I explained, you are hitting the CHECK() here. [1] ASAN stack traces are not always the most accurate. If you do a normal debug pdfium_test build, gdb can give a better stack trace. [1] https://pdfium.googlesource.com/pdfium.git/+/072d829e2cd1586645022498a01a61db83a2db4d/third_party/base/span.h#247
,
Sep 27
I found a strange problem in my gdb, asan is right, no OOB write here. This testcase is just hitting CHECK() in https://pdfium.googlesource.com/pdfium.git/+/072d829e2cd1586645022498a01a61db83a2db4d/third_party/base/span.h#247 Sorry for my mistake.
,
Sep 27
Dropping severity since it's not an OOB write. It would be good to merge the fix to M70.
,
Sep 28
Do we need a merge request here?
,
Sep 28
Sure, let's merge https://pdfium.googlesource.com/pdfium/+/73e97f4fac2f4f591ff62e70377a80fd40b5f6f3
,
Sep 28
This bug requires manual review: M70 has already been promoted to the beta branch, so this requires manual review Please contact the milestone owner if you have questions. Owners: benmason@(Android), kariahda@(iOS), geohsu@(ChromeOS), abdulsyed@(Desktop) For more details visit https://www.chromium.org/issue-tracking/autotriage - Your friendly Sheriffbot
,
Sep 29
Please mark security bugs as fixed as soon as the fix lands, and before requesting merges. This update is based on the merge- labels applied to this issue. Please reopen if this update was incorrect. For more details visit https://www.chromium.org/issue-tracking/autotriage - Your friendly Sheriffbot
,
Sep 30
,
Oct 1
branch:3538
,
Oct 1
The following revision refers to this bug: https://pdfium.googlesource.com/pdfium/+/13b08aa11de74120909b871b987d010f33cd0bc6 commit 13b08aa11de74120909b871b987d010f33cd0bc6 Author: Lei Zhang <thestig@chromium.org> Date: Mon Oct 01 17:47:52 2018 M70: Avoid CHECK in fpdf_parser_decode.cpp (memcpy empty span) Given a span of size N, memcpy(dest, &span[N], 0) ought to be a no-op, but since we compute span[N] before checking for zero length, we hit an assert. The correct idiom should be to create a sub-span, which allows specifying N, but only when the size is 0. Bug: chromium:879910 , chromium:889356 Change-Id: Ic6f368109a5c2f1e13a5f638c6a233769e2ad41b Reviewed-on: https://pdfium-review.googlesource.com/41930 Commit-Queue: Tom Sepez <tsepez@chromium.org> Reviewed-by: Lei Zhang <thestig@chromium.org> (cherry picked from commit 73e97f4fac2f4f591ff62e70377a80fd40b5f6f3) Reviewed-on: https://pdfium-review.googlesource.com/43271 [modify] https://crrev.com/13b08aa11de74120909b871b987d010f33cd0bc6/core/fpdfapi/parser/fpdf_parser_decode.cpp
,
Oct 1
,
Oct 2
,
Oct 3
VRP panel look a look and agreed this isn't a security bug.
,
Oct 8
,
Jan 5
This bug has been closed for more than 14 weeks. Removing security view restrictions. For more details visit https://www.chromium.org/issue-tracking/autotriage - Your friendly Sheriffbot |
|||||||||||||||||
►
Sign in to add a comment |
|||||||||||||||||
Comment 1 by dominickn@chromium.org
, Sep 26Components: Internals>Plugins>PDF
Labels: Security_Severity-High Security_Impact-Head OS-Android OS-Chrome OS-Linux OS-Mac OS-Windows Pri-1
Owner: rharrison@chromium.org
Status: Assigned (was: Unconfirmed)