kax_file_c, ElementReader: only delete returned upper-level element if found

The `EbmlElement::Read` function returns two values via reference
parameters. They're called `UpperEltFound` (an integer) and
`FoundElt` (a pointer to an EBML element). They're used for passing
back the first element found (if any) that is not a child of the
element currently being read so that the calling code can continue
parsing the file using the upper-level element.

If the calling code doesn't need that element, it has to delete it
itself. However, the code must not simply rely on the `FoundElt`
pointer being not null as the `Read` function assigns temporary
results to that variable. Depending on the file content, that
temporary element may have already been deleted by the `Read`
function. When the calling code then simply deletes `FoundElt` itself,
this leads to a typical case of use-after-free.

Instead the calling code must only work with the returned `FoundElt`
pointer if the other returned value, `UpperEltFound`, trueish in the
C++ sense (if it isn't 0). Then and only then may the calling code
attempt to delete the object `FoundElt` points to.

This vulnerability allows arbitrary code execution via specially
crafted Matroska files. It was reported by Cisco TALOS on 2018-10-25
and is known as TALOS 2018-0694.
This commit is contained in:
Moritz Bunkus 2018-10-25 21:59:24 +02:00
parent fac242710e
commit 43021d16c7
No known key found for this signature in database
GPG Key ID: 74AF00ADF2E32C85
5 changed files with 25 additions and 3 deletions

11
NEWS.md
View File

@ -1,3 +1,14 @@
# Version ?
## Bug fixes
* mkvmerge, mkvinfo, mkvextract, mkvpropedit, MKVToolNix GUI's info tool &
chapter editor: fixed a case of memory being accessed after it had been
freed earlier. This can be triggered by specially crafted Matroska files and
lead to arbitrary code execution. The vulnerability was reported as Cisco
TALOS 2018-0694 on 2018-10-25.
# Version 28.1.0 "Morning Child" 2018-10-23
## Bug fixes

View File

@ -152,13 +152,13 @@ kax_file_c::read_one_element() {
auto l2 = static_cast<EbmlElement *>(nullptr);
try {
l1->Read(*m_es.get(), EBML_INFO_CONTEXT(*callbacks), upper_lvl_el, l2, true);
if (!found_in(*l1, l2))
if (upper_lvl_el && !found_in(*l1, l2))
delete l2;
} catch (std::runtime_error &e) {
mxdebug_if(m_debug_resync, boost::format("exception reading element data: %1%\n") % e.what());
m_in.setFilePointer(l1->GetElementPosition() + 1);
if (!found_in(*l1, l2))
if (upper_lvl_el && !found_in(*l1, l2))
delete l2;
return {};
}

View File

@ -46,7 +46,8 @@ ElementReader::run() {
m_element.Read(es, EBML_INFO_CONTEXT(*callbacks), upper_lvl, upper_lvl_el, true);
delete upper_lvl_el;
if (upper_lvl)
delete upper_lvl_el;
} catch (mtx::mm_io::exception &) {
}

View File

@ -507,3 +507,4 @@ T_658X_av1:20347e54bac4d1b0fe82d1f2f6c17c4d+8a967d44a1de7c00bf8be24156802f4f:pas
T_659av1_timing_info_in_bitstream:b0b31fd8f8f569f7dcb7f29a3960050d-15361e7c74dfdbd59ffe96009b44a63f:passed:20181007-235434:0.016544501
T_660propedit_replace_one_byte_with_ebmlvoid_all_surrounding_elements_coded_size_length_8:a16d7aa5d00d120d20c4c3c718e1b00b:passed:20181020-160502:0.0
T_661av1_in_matroska_by_mkvmerge_28_0_0:66667a5dd1a2cafb3aa37ce41aedfbf7:passed:20181021-225056:0.008359871
T_662cisco_talos_2018_0694:2bacc50e6e28fb2a92d2abf2583405f5-3292227553ffd194cd6c24cf07413fe2:passed:20181025-215511:0.024040919

View File

@ -0,0 +1,9 @@
#!/usr/bin/ruby -w
# T_662cisco_talos_2018_0694
describe "mkvinfo / Cisco TALOS 2018-0694 use after free"
file = "data/segfaults-assertions/cisco-talos-2018-0694.mkv"
test_merge file
test_info file, :args => "-v -v"