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_lexer.cpp | 89 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 81 insertions(+), 8 deletions(-) (limited to 'xfa/fxfa/fm2js/xfa_lexer.cpp') 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; -- cgit v1.2.3