https://bugs.documentfoundation.org/show_bug.cgi?id=173267
Bug ID: 173267
Summary: Crash when opening a PPTX containing a table whose
a:tableStyleId GUID is not a predefined table style
and is not defined in ppt/tableStyles.xml (Impress,
oox import, NULL dereference)
Product: LibreOffice
Version: 27.2.0.0 alpha0+ master
Hardware: All
OS: All
Status: UNCONFIRMED
Severity: normal
Priority: medium
Component: Base
Assignee: [email protected]
Reporter: [email protected]
Description:
Dear LibreOffice-Team,
A PPTX table whose `a:tableStyleId` is neither defined in the presentation's
own `ppt/tableStyles.xml` nor one of the 74 predefined style GUIDs crashes the
Impress import with a NULL dereference.
One wrong hex digit in an otherwise valid style id is enough, and the id does
not have to come from a mutation.
This bug was found with a new fuzzing approach via the `libreoffice` oss-fuzz
target `pptxfuzzer` using the `core` master branch at commit
`50ae505eb3ef23a3ff4a52a62d41a6f0fa6683ab`, built by OSS-Fuzz with ASan.
`CreateTableStyle` looks the style id up in `mStyleIdMap` and dereferences the
iterator without comparing it against `end()`,
`oox/source/drawingml/table/predefined-table-styles.cxx`:
```c++
427 auto it = mStyleIdMap.find(styleId);
428 OUString style_name = it->second.first;
429 OUString accent_name = it->second.second;
```
`mStyleIdMap` is a fixed table of the 74 GUIDs PowerPoint ships (declared at
line 37), and `styleId` comes straight out of the document.
When the id is unknown, `it` is `end()` and the `OUString` copy constructor
faults:
```
==42==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000018
==42==The signal is caused by a READ memory access.
==42==Hint: address points to the zero page.
SCARINESS: 10 (null-deref)
#0 in OUString include/rtl/ustring.hxx:199:21
#1 in CreateTableStyle(rtl::OUString const&)
oox/source/drawingml/table/predefined-table-styles.cxx:428:27
#2 in oox::drawingml::table::TableProperties::getUsedTableStyle(...)
oox/source/drawingml/table/tableproperties.cxx:112:35
#3 in oox::drawingml::table::TableProperties::pushToPropSet(...)
oox/source/drawingml/table/tableproperties.cxx:137:35
#4 in oox::drawingml::Shape::createAndInsert(...)
oox/source/drawingml/shape.cxx:1679:35
#5 in oox::ppt::PPTShape::addShape(...) oox/source/ppt/pptshape.cxx:529:41
#6 in oox::ppt::SlidePersist::createXShapes(...)
oox/source/ppt/slidepersist.cxx:201:28
```
The caller reaches it by design for exactly the case the document controls,
`oox/source/drawingml/table/tableproperties.cxx`:
```c++
109 //if the pptx just has table style id, but no table style
content, we will create the table style ourselves
110 if (!pTableStyle)
111 {
112 rTableStyleToDelete = CreateTableStyle(aStyleId);
113 pTableStyle = rTableStyleToDelete.get();
114 }
```
Line 427 is the first unchecked dereference, not the only one.
There are eleven more `mStyleIdMap.find(styleId)->second` dereferences at lines
460, 525, 576, 611, 648, 685, 733, 773, 800, 843 and 886, all of them inside
branches that are only entered after line 428 has set `style_name`.
The attached `minimal_unknown_tablestyleid.pptx` is a hand-built presentation
holding one single-cell table whose style id is
`{4C22544A-7EE6-4342-B048-85BDC9FD1C3A}`.
`control_known_tablestyleid.pptx` is the same presentation with
`{5C22544A-7EE6-4342-B048-85BDC9FD1C3A}`, the real id of Medium-Style-2
Accent1.
The two presentations differ in exactly one byte of `ppt/slides/slide1.xml`,
the `4` against the `5`, and in no other part, and every part of both is
well-formed XML.
The fuzzer found it the same way, by flipping the leading hex digit of a style
id the seed already carried, in
`crash-1f341145db0fd98ad457589eb964c97f7472d5d6`.
That testcase still defines `{5C22544A-7EE6-4342-B048-85BDC9FD1C3A}` in its
`ppt/tableStyles.xml` while its slide asks for
`{4C22544A-7EE6-4342-B048-85BDC9FD1C3A}`, so the search at line 101 finds
nothing and line 112 is reached.
`unzip -t` reports a bad CRC-32 on eleven of its thirty-five parts, because the
fuzzer rewrote them in place without fixing the checksums, so the hand-built
presentations are the artifacts to reproduce from.
Reaching `CreateTableStyle` needs the presentation to have a
`ppt/tableStyles.xml` part, since `getUsedTableStyle` only takes this path when
`rBase.getTableStyles()` is non-null (`tableproperties.cxx:96`), so both
attached presentations carry an empty `a:tblStyleLst`.
The same fuzz target produced a second, unrelated defect in the comment import,
reported separately as bug 164.
## Fix
We are not shipping a patch, but the suggested fix is to refuse an id the table
does not know, before any of the twelve dereferences:
```diff
std::unique_ptr<TableStyle> CreateTableStyle(const OUString& styleId)
{
+ // The style id comes straight from the document and need not be one of
the
+ // predefined ones; every mStyleIdMap.find(styleId) below assumes it is.
+ if (mStyleIdMap.find(styleId) == mStyleIdMap.end())
+ return nullptr;
+
std::unique_ptr<TableStyle> pTableStyle;
```
Returning nothing needs no new handling at the call site: `getUsedTableStyle`
already tests `pTableStyle` right after the call and falls back to
`theDefaultTableStyle`, `tableproperties.cxx:117-121`.
That is the only call site of `CreateTableStyle` in the tree.
## Reproduce
The original fuzzer testcase, its CASR report and the two hand-built
presentations are attached.
```bash
export DOCKER_DEFAULT_PLATFORM=linux/amd64 # if on mac
git clone https://github.com/google/oss-fuzz.git
cd oss-fuzz
python3 infra/helper.py build_image libreoffice
python3 infra/helper.py build_fuzzers --sanitizer address libreoffice
python3 infra/helper.py reproduce libreoffice pptxfuzzer
crash-1f341145db0fd98ad457589eb964c97f7472d5d6
python3 infra/helper.py reproduce libreoffice pptxfuzzer
minimal_unknown_tablestyleid.pptx
python3 infra/helper.py reproduce libreoffice pptxfuzzer
control_known_tablestyleid.pptx
```
We tested against OSS-Fuzz at commit
`a4df12d70b5420567d893b3f53e5818a74df5db7`, default `linux/amd64` containers,
and `core` master at commit `50ae505eb3ef23a3ff4a52a62d41a6f0fa6683ab`.
Found by the CISPA Fandango-Team while triaging OSS-Fuzz findings for
libreoffice.
Steps to Reproduce:
<-- Download and unzip the Reproduce.zip -->
export DOCKER_DEFAULT_PLATFORM=linux/amd64 # if on mac
git clone https://github.com/google/oss-fuzz.git
cd oss-fuzz
python3 infra/helper.py build_image libreoffice
python3 infra/helper.py build_fuzzers --sanitizer address libreoffice
python3 infra/helper.py reproduce libreoffice pptxfuzzer
crash-1f341145db0fd98ad457589eb964c97f7472d5d6
python3 infra/helper.py reproduce libreoffice pptxfuzzer
minimal_unknown_tablestyleid.pptx
python3 infra/helper.py reproduce libreoffice pptxfuzzer
control_known_tablestyleid.pptx
Actual Results:
==42==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000018
==42==The signal is caused by a READ memory access.
==42==Hint: address points to the zero page.
SCARINESS: 10 (null-deref)
#0 in OUString include/rtl/ustring.hxx:199:21
#1 in CreateTableStyle(rtl::OUString const&)
oox/source/drawingml/table/predefined-table-styles.cxx:428:27
#2 in oox::drawingml::table::TableProperties::getUsedTableStyle(...)
oox/source/drawingml/table/tableproperties.cxx:112:35
#3 in oox::drawingml::table::TableProperties::pushToPropSet(...)
oox/source/drawingml/table/tableproperties.cxx:137:35
#4 in oox::drawingml::Shape::createAndInsert(...)
oox/source/drawingml/shape.cxx:1679:35
#5 in oox::ppt::PPTShape::addShape(...) oox/source/ppt/pptshape.cxx:529:41
#6 in oox::ppt::SlidePersist::createXShapes(...)
oox/source/ppt/slidepersist.cxx:201:28
Expected Results:
No crash
Reproducible: Always
User Profile Reset: No
Additional Info:
This bug was found with a new fuzzing approach via the `libreoffice` oss-fuzz
target `pptxfuzzer` using the `core` master branch at commit
`50ae505eb3ef23a3ff4a52a62d41a6f0fa6683ab`, built by OSS-Fuzz with ASan.
--
You are receiving this mail because:
You are the assignee for the bug.