QTextMarkdownImporter: fix use after free; add fuzz-generated tests

It was possible to end up with a dangling pointer in m_listStack.
This is now avoided by using QPointer and doing nullptr checks before
accessing any QTextList pointer stored there.

We have 2 specimens of garbage that caused crashes before; now they don't.
But only fuzz20450 triggered the dangling pointer in the list stack.
The crash caused by fuzz20580 was fixed by updating md4c from upstream:
4b0fc03077

Change-Id: I8e1eca23b281256a03aea0f55e9ae20f1bdd2a38
Reviewed-by: Robert Loehning <robert.loehning@qt.io>
This commit is contained in:
Shawn Rutledge 2020-02-24 16:23:27 +01:00
parent eaf7f572bf
commit 7447e2b337
6 changed files with 38 additions and 3 deletions

View File

@ -577,7 +577,10 @@ void QTextMarkdownImporter::insertBlock()
QTextBlockFormat blockFormat;
if (!m_listStack.isEmpty() && !m_needsInsertList && m_listItem) {
QTextList *list = m_listStack.top();
if (list)
blockFormat = list->item(list->count() - 1).blockFormat();
else
qWarning() << "attempted to insert into a list that no longer exists";
}
if (m_blockQuoteDepth) {
blockFormat.setProperty(QTextFormat::BlockQuoteLevel, m_blockQuoteDepth);
@ -607,7 +610,7 @@ void QTextMarkdownImporter::insertBlock()
}
if (m_needsInsertList) {
m_listStack.push(m_cursor->createList(m_listFormat));
} else if (!m_listStack.isEmpty() && m_listItem) {
} else if (!m_listStack.isEmpty() && m_listItem && m_listStack.top()) {
m_listStack.top()->add(m_cursor->block());
}
m_needsInsertList = false;

View File

@ -113,7 +113,7 @@ private:
#endif
QString m_blockCodeLanguage;
QVector<int> m_nonEmptyTableCells; // in the current row
QStack<QTextList *> m_listStack;
QStack<QPointer<QTextList>> m_listStack;
QStack<QTextCharFormat> m_spanFormatStack;
QFont m_monoFont;
QPalette m_palette;

View File

@ -0,0 +1,5 @@
<t><EFBFBD>
* <20>
<09>
* <20>

View File

@ -0,0 +1 @@
| --:| <?`?><?|`

View File

@ -5,5 +5,7 @@ SOURCES += tst_qtextmarkdownimporter.cpp
TESTDATA += \
data/thematicBreaks.md \
data/headingBulletsContinuations.md \
data/fuzz20450.md \
data/fuzz20580.md \
DEFINES += SRCDIR=\\\"$$PWD\\\"

View File

@ -57,6 +57,8 @@ private slots:
void lists();
void avoidBlankLineAtBeginning_data();
void avoidBlankLineAtBeginning();
void pathological_data();
void pathological();
};
void tst_QTextMarkdownImporter::headingBulletsContinuations()
@ -256,5 +258,27 @@ void tst_QTextMarkdownImporter::avoidBlankLineAtBeginning() // QTBUG-81060
QCOMPARE(i, expectedNumberOfParagraphs);
}
void tst_QTextMarkdownImporter::pathological_data()
{
QTest::addColumn<QString>("warning");
QTest::newRow("fuzz20450") << "attempted to insert into a list that no longer exists";
QTest::newRow("fuzz20580") << "";
}
void tst_QTextMarkdownImporter::pathological() // avoid crashing on crazy input
{
QFETCH(QString, warning);
QString filename = QLatin1String("data/") + QTest::currentDataTag() + QLatin1String(".md");
QFile f(QFINDTESTDATA(filename));
QVERIFY(f.open(QFile::ReadOnly));
#ifdef QT_NO_DEBUG
Q_UNUSED(warning)
#else
if (!warning.isEmpty())
QTest::ignoreMessage(QtWarningMsg, warning.toLatin1());
#endif
QTextDocument().setMarkdown(f.readAll());
}
QTEST_MAIN(tst_QTextMarkdownImporter)
#include "tst_qtextmarkdownimporter.moc"