From 2eef64cba5c8e08a9e625f4aba5a7fbdc8e62bad Mon Sep 17 00:00:00 2001 From: Dan Sinclair Date: Tue, 16 May 2017 11:45:23 -0400 Subject: Do not walk off end of formcalc string MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The fm2js code takes a pointer to the input string and then walks along that pointer. There are currently no checks to verify we haven't walked off the end of the pointer into random memory. If this happens, we can end up allocating large chunks of memory and copying random bits. BUG=chromium:721533 Change-Id: Ia61fe96c1ff9eb9ded63cf8326b7be44986bd9e1 Reviewed-on: https://pdfium-review.googlesource.com/5550 Commit-Queue: dsinclair Reviewed-by: Nicolás Peña Reviewed-by: Lei Zhang --- xfa/fxfa/fm2js/xfa_error.cpp | 1 + xfa/fxfa/fm2js/xfa_error.h | 1 + xfa/fxfa/fm2js/xfa_lexer.cpp | 89 ++++++++++++++++++++++++++++++++++++++++---- xfa/fxfa/fm2js/xfa_lexer.h | 1 + 4 files changed, 84 insertions(+), 8 deletions(-) diff --git a/xfa/fxfa/fm2js/xfa_error.cpp b/xfa/fxfa/fm2js/xfa_error.cpp index 1d31ce6958..ea0511a89a 100644 --- a/xfa/fxfa/fm2js/xfa_error.cpp +++ b/xfa/fxfa/fm2js/xfa_error.cpp @@ -17,3 +17,4 @@ const wchar_t kFMErrExpectedNonEmptyExpression[] = L"expected non-empty expression"; const wchar_t kFMErrLongAssignmentChain[] = L"long assignment chains are unsupported"; +const wchar_t kFMErrEndOfInput[] = L"unexpected end of input"; diff --git a/xfa/fxfa/fm2js/xfa_error.h b/xfa/fxfa/fm2js/xfa_error.h index b6621da440..27ed1879cf 100644 --- a/xfa/fxfa/fm2js/xfa_error.h +++ b/xfa/fxfa/fm2js/xfa_error.h @@ -18,6 +18,7 @@ extern const wchar_t kFMErrExpectedEndIf[]; extern const wchar_t kFMErrUnexpectedExpression[]; extern const wchar_t kFMErrExpectedNonEmptyExpression[]; extern const wchar_t kFMErrLongAssignmentChain[]; +extern const wchar_t kFMErrEndOfInput[]; class CXFA_FMErrorInfo { public: diff --git a/xfa/fxfa/fm2js/xfa_lexer.cpp b/xfa/fxfa/fm2js/xfa_lexer.cpp index 069c32f028..dfac51ab2c 100644 --- a/xfa/fxfa/fm2js/xfa_lexer.cpp +++ b/xfa/fxfa/fm2js/xfa_lexer.cpp @@ -96,12 +96,21 @@ CXFA_FMToken::CXFA_FMToken(uint32_t uLineNum) CXFA_FMLexer::CXFA_FMLexer(const CFX_WideStringC& wsFormCalc, CXFA_FMErrorInfo* pErrorInfo) - : m_ptr(wsFormCalc.c_str()), m_uCurrentLine(1), m_pErrorInfo(pErrorInfo) {} + : m_ptr(wsFormCalc.c_str()), + m_end(m_ptr + wsFormCalc.GetLength() - 1), + m_uCurrentLine(1), + m_pErrorInfo(pErrorInfo) {} CXFA_FMLexer::~CXFA_FMLexer() {} CXFA_FMToken* CXFA_FMLexer::NextToken() { - m_pToken = Scan(); + // Make sure we don't walk off the end of the string. + if (m_ptr > m_end) { + m_pToken = pdfium::MakeUnique(m_uCurrentLine); + m_pToken->m_type = TOKeof; + } else { + m_pToken = Scan(); + } return m_pToken.get(); } @@ -115,6 +124,10 @@ std::unique_ptr CXFA_FMLexer::Scan() { } while (1) { + // Make sure we don't walk off the end of the string. + if (m_ptr > m_end) + return p; + ch = *m_ptr; if (!IsValid(m_ptr)) { Error(kFMErrUnsupportedChar, ch); @@ -158,6 +171,11 @@ std::unique_ptr CXFA_FMLexer::Scan() { } case '=': ++m_ptr; + if (m_ptr > m_end) { + Error(kFMErrEndOfInput); + return p; + } + if (IsValid(m_ptr)) { ch = *m_ptr; if (ch == '=') { @@ -173,6 +191,11 @@ std::unique_ptr CXFA_FMLexer::Scan() { return p; case '<': ++m_ptr; + if (m_ptr > m_end) { + Error(kFMErrEndOfInput); + return p; + } + if (IsValid(m_ptr)) { ch = *m_ptr; if (ch == '=') { @@ -191,6 +214,11 @@ std::unique_ptr CXFA_FMLexer::Scan() { return p; case '>': ++m_ptr; + if (m_ptr > m_end) { + Error(kFMErrEndOfInput); + return p; + } + if (IsValid(m_ptr)) { ch = *m_ptr; if (ch == '=') { @@ -246,6 +274,11 @@ std::unique_ptr CXFA_FMLexer::Scan() { return p; case '/': { ++m_ptr; + if (m_ptr > m_end) { + Error(kFMErrEndOfInput); + return p; + } + if (!IsValid(m_ptr)) { ch = *m_ptr; Error(kFMErrUnsupportedChar, ch); @@ -261,6 +294,11 @@ std::unique_ptr CXFA_FMLexer::Scan() { } case '.': ++m_ptr; + if (m_ptr > m_end) { + Error(kFMErrEndOfInput); + return p; + } + if (IsValid(m_ptr)) { ch = *m_ptr; if (ch == '.') { @@ -316,6 +354,11 @@ const wchar_t* CXFA_FMLexer::String(CXFA_FMToken* t, const wchar_t* p) { const wchar_t* pStart = p; ++p; + if (p > m_end) { + Error(kFMErrEndOfInput); + return p; + } + uint16_t ch = *p; while (ch) { if (!IsValid(p)) { @@ -324,13 +367,18 @@ const wchar_t* CXFA_FMLexer::String(CXFA_FMToken* t, const wchar_t* p) { Error(kFMErrUnsupportedChar, ch); return p; } + + ++p; + if (p > m_end) { + Error(kFMErrEndOfInput); + return p; + } + if (ch != '"') { - ++p; ch = *p; continue; } - ++p; if (!IsValid(p)) { ch = *p; t->m_wstring = CFX_WideStringC(pStart, (p - pStart)); @@ -342,6 +390,10 @@ const wchar_t* CXFA_FMLexer::String(CXFA_FMToken* t, const wchar_t* p) { break; ++p; + if (p > m_end) { + Error(kFMErrEndOfInput); + return p; + } ch = *p; } t->m_wstring = CFX_WideStringC(pStart, (p - pStart)); @@ -352,6 +404,11 @@ const wchar_t* CXFA_FMLexer::Identifiers(CXFA_FMToken* t, const wchar_t* p) { const wchar_t* pStart = p; uint16_t ch = *p; ++p; + if (p > m_end) { + Error(kFMErrEndOfInput); + return p; + } + if (!IsValid(p)) { t->m_wstring = CFX_WideStringC(pStart, (p - pStart)); Error(kFMErrUnsupportedChar, ch); @@ -375,6 +432,10 @@ const wchar_t* CXFA_FMLexer::Identifiers(CXFA_FMToken* t, const wchar_t* p) { break; } ++p; + if (p > m_end) { + Error(kFMErrEndOfInput); + return p; + } } t->m_wstring = CFX_WideStringC(pStart, (p - pStart)); t->m_type = IsKeyword(t->m_wstring); @@ -383,18 +444,30 @@ const wchar_t* CXFA_FMLexer::Identifiers(CXFA_FMToken* t, const wchar_t* p) { const wchar_t* CXFA_FMLexer::Comment(const wchar_t* p) { ++p; + + if (p > m_end) { + Error(kFMErrEndOfInput); + return p; + } + unsigned ch = *p; while (ch) { - if (ch == 0x0D) { + if (ch == L'\r') { ++p; + if (p > m_end) + Error(kFMErrEndOfInput); return p; } - if (ch == 0x0A) { + + ++p; + if (p > m_end) { + Error(kFMErrEndOfInput); + return p; + } + if (ch == L'\n') { ++m_uCurrentLine; - ++p; return p; } - ++p; ch = *p; } return p; diff --git a/xfa/fxfa/fm2js/xfa_lexer.h b/xfa/fxfa/fm2js/xfa_lexer.h index 5dd10c2d63..0db9de58a9 100644 --- a/xfa/fxfa/fm2js/xfa_lexer.h +++ b/xfa/fxfa/fm2js/xfa_lexer.h @@ -126,6 +126,7 @@ class CXFA_FMLexer { std::unique_ptr Scan(); const wchar_t* m_ptr; + const wchar_t* const m_end; uint32_t m_uCurrentLine; std::unique_ptr m_pToken; CXFA_FMErrorInfo* m_pErrorInfo; -- cgit v1.2.3