diff options
author | Dan Sinclair <dsinclair@chromium.org> | 2017-05-16 11:45:23 -0400 |
---|---|---|
committer | Chromium commit bot <commit-bot@chromium.org> | 2017-05-16 16:00:10 +0000 |
commit | 2eef64cba5c8e08a9e625f4aba5a7fbdc8e62bad (patch) | |
tree | 38a70cf1d91fc56a64a4525c041447c203b07f49 /xfa | |
parent | 2a835b7b902bc0b61b1a3618f5c82b91571ecd72 (diff) | |
download | pdfium-2eef64cba5c8e08a9e625f4aba5a7fbdc8e62bad.tar.xz |
Do not walk off end of formcalc string
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 <dsinclair@chromium.org>
Reviewed-by: Nicolás Peña <npm@chromium.org>
Reviewed-by: Lei Zhang <thestig@chromium.org>
Diffstat (limited to 'xfa')
-rw-r--r-- | xfa/fxfa/fm2js/xfa_error.cpp | 1 | ||||
-rw-r--r-- | xfa/fxfa/fm2js/xfa_error.h | 1 | ||||
-rw-r--r-- | xfa/fxfa/fm2js/xfa_lexer.cpp | 89 | ||||
-rw-r--r-- | 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<CXFA_FMToken>(m_uCurrentLine); + m_pToken->m_type = TOKeof; + } else { + m_pToken = Scan(); + } return m_pToken.get(); } @@ -115,6 +124,10 @@ std::unique_ptr<CXFA_FMToken> 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_FMToken> 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_FMToken> 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_FMToken> 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_FMToken> 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_FMToken> 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<CXFA_FMToken> Scan(); const wchar_t* m_ptr; + const wchar_t* const m_end; uint32_t m_uCurrentLine; std::unique_ptr<CXFA_FMToken> m_pToken; CXFA_FMErrorInfo* m_pErrorInfo; |