|
|
Message-ID: <CAB6DpjW0BqVNJqBvSnKuA6bbAEpoEMvK6ef0ALEbhndYVubbCA@mail.gmail.com>
Date: Mon, 16 Jul 2018 15:10:41 +0800
From: Ruikai Liu <lrk700@...il.com>
To: oss-security@...ts.openwall.com
Subject: Integer underflow/overflow in MP4v2 2.0.0
Hi,
Integer underflow and overflow are found in MP4v2 2.0.0, a legacy library
dealing with MP4 media file.
========= Underflow =========
Atom is the basic element of MP4. However there's an integer underflow when
parsing an atom(src/mp4atom.cpp):
121 uint64_t dataSize = file.ReadUInt32();
...
146 dataSize -= hdrSize;
...
151 if (pos + hdrSize + dataSize > pParentAtom->GetEnd()) {
...
164 // skip to end of atom
165 dataSize = pParentAtom->GetEnd() - pos - hdrSize;
166 }
If `dataSize` read from file is less than `hdrSize`, then underflow happens
and it becomes a very large unsigned integer at line 146. Yet the check at
line 151 would still be passed, which results in an corrupted atom with
extremely large size.
========= Overflow =========
`ftyp` is an atom that describes the version info of the MP4 file. It will
allocate memory for compatible brands according to the atom's size:
54 void MP4FtypAtom::Read()
55 {
56 compatibleBrands.SetCount( (m_size - 8) / 4 ); // brands array
fills rest of atom
57 MP4Atom::Read();
58 }
342 void MP4StringProperty::SetCount(uint32_t count)
343 {
344 uint32_t oldCount = m_values.Size();
345
346 m_values.Resize(count);
347
348 for (uint32_t i = oldCount; i < count; i++) {
349 m_values[i] = NULL;
350 }
351 }
`Resize` here is a wrapper of `realloc`:
102 void Resize(MP4ArrayIndex newSize) { \
103 m_numElements = newSize; \
104 m_maxNumElements = newSize; \
105 m_elements = (type*)MP4Realloc(m_elements, \
106 m_maxNumElements * sizeof(type)); \
107 } \
We notice that an integer overflow could happen when calculating
`m_maxNumElements * sizeof(type)`. So the allocation may return a buffer
smaller than needed, and later operations on the buffer could result in
invalid memory reference, like setting values to be NULL in
`MP4StringProperty::SetCount`. This is the case for 64-bits program which
allows memory allocation for large(~4GB) size.
Things are a little different for 32-bits. In this case `realloc` would
fail and throws an exception:
74 inline void* MP4Realloc(void* p, uint32_t newSize) {
75 // workaround library bug
76 if (p == NULL && newSize == 0) {
77 return NULL;
78 }
79
80 void* temp = realloc(p, newSize);
81 if (temp == NULL && newSize > 0) {
82 throw new PlatformException("malloc
failed",errno,__FILE__,__LINE__,__FUNCTION__);
83 }
84 return temp;
85 }
And the destructor the `MP4StringProperty` would be invoked:
334 MP4StringProperty::~MP4StringProperty()
335 {
336 uint32_t count = GetCount();
337 for (uint32_t i = 0; i < count; i++) {
338 MP4Free(m_values[i]);
339 }
340 }
But the count here is still the extremly large number we set before, and
the for-loop would certainly have some invalid addresses been freed.
========= POC =========
Here's a very simple POC file:
root@...ian:~# hexdump -Cv c2.mp4
00000000 00 00 00 07 66 74 79 70 6d 70 34 32 41 41 41 41
|....ftypmp42AAAA|
00000010 41 41 41 41 41 41 41 41 |AAAAAAAA|
00000018
The size of the `ftyp` box is 7(the first 4 bytes), which is smalller than
the header size(8 bytes). Therefore the `dataSize` for this atom would
become -1=0xffffffffffffffff.
This POC file crashes both 32-bits and 64-bits mp4info.
========= Fix =========
For the underflow, we could check if `dataSize >= hdrSize` satisfies:
--- src/mp4atom.cpp 2018-07-16 14:54:33.513635593 +0800
+++ ../mp4v2-2.0.0-orig/src/mp4atom.cpp 2012-05-21 06:11:53.000000000
+0800
@@ -143,9 +143,6 @@
dataSize = file.GetSize() - pos;
}
- if(dataSize < hdrSize) {
- throw new Exception( "invalid dataSize", __FILE__, __LINE__,
__FUNCTION__ );
- }
dataSize -= hdrSize;
log.verbose1f("\"%s\": type = \"%s\" data-size = %" PRIu64 " (0x%"
PRIx64 ") hdr %u",
For the overflow, we could check the result of the integer multiplication:
--- src/mp4array.h 2018-07-16 15:00:51.333620723 +0800
+++ ../mp4v2-2.0.0-orig-/src/mp4array.h 2012-05-21 06:11:53.000000000
+0800
@@ -102,11 +102,8 @@
void Resize(MP4ArrayIndex newSize) { \
m_numElements = newSize; \
m_maxNumElements = newSize; \
- uint32_t mul = newSize * sizeof(type); \
- if(mul / newSize != sizeof(type)) \
- throw new Exception("multiplication overflow", __FILE__,
__LINE__, __FUNCTION__);\
m_elements = (type*)MP4Realloc(m_elements, \
- mul); \
+ m_maxNumElements * sizeof(type)); \
} \
========= Reference =========
https://code.google.com/archive/p/mp4v2/
--
Best regards,
Ruikai Liu
Powered by blists - more mailing lists
Please check out the Open Source Software Security Wiki, which is counterpart to this mailing list.
Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.