Skip to content

Commit eabad85

Browse files
authored
Merge pull request #73 from cinema-ONE/mpo-jpeg-error-handler
Stop malformed MPO files terminating Kodi, and bounds-check the MP parser
2 parents 2b0e343 + 1e4e153 commit eabad85

1 file changed

Lines changed: 39 additions & 1 deletion

File tree

src/MPOPicture.cpp

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,30 @@
1010

1111
#include "../lib/TinyEXIF/TinyEXIF.h"
1212

13+
#include <csetjmp>
1314
#include <iostream>
1415
#include <kodi/Filesystem.h>
1516

17+
namespace
18+
{
19+
20+
// libjpeg's default error_exit calls exit(), and libmpo installs it via
21+
// jpeg_std_error() without overriding it, so a malformed file terminates Kodi
22+
// rather than failing the decode. mpo_decompress_error_exit() can only replace
23+
// the function pointer, not attach state to it, so the jump target is
24+
// thread-local; each decoder instance is driven from one thread at a time.
25+
thread_local std::jmp_buf s_jpegEscape;
26+
27+
void MpoFatalError(j_common_ptr cinfo)
28+
{
29+
char message[JMSG_LENGTH_MAX] = {};
30+
(*cinfo->err->format_message)(cinfo, message);
31+
kodi::Log(ADDON_LOG_ERROR, "libjpeg: %s", message);
32+
std::longjmp(s_jpegEscape, 1);
33+
}
34+
35+
} // namespace
36+
1637
MPOPicture::MPOPicture(const kodi::addon::IInstanceInfo& instance)
1738
: CInstanceImageDecoder(instance)
1839
{
@@ -36,8 +57,15 @@ bool MPOPicture::SupportsFile(const std::string& file)
3657

3758
mpo_decompress_struct mpoinfo;
3859
mpo_create_decompress(&mpoinfo);
60+
mpo_decompress_error_exit(&mpoinfo, MpoFatalError);
61+
if (setjmp(s_jpegEscape))
62+
{
63+
mpo_destroy_decompress(&mpoinfo);
64+
return false;
65+
}
66+
3967
mpo_mem_src(&mpoinfo, buffer.data(), buffer.size());
40-
bool ret = mpo_read_header(&mpoinfo);
68+
const bool ret = mpo_read_header(&mpoinfo);
4169
mpo_destroy_decompress(&mpoinfo);
4270
return ret;
4371
}
@@ -139,6 +167,13 @@ bool MPOPicture::LoadImageFromMemory(const std::string& mimetype,
139167
m_data.resize(bufSize);
140168
std::copy(buffer, buffer + bufSize, m_data.begin());
141169
mpo_create_decompress(&m_mpoinfo);
170+
mpo_decompress_error_exit(&m_mpoinfo, MpoFatalError);
171+
if (setjmp(s_jpegEscape))
172+
{
173+
mpo_destroy_decompress(&m_mpoinfo);
174+
return false;
175+
}
176+
142177
mpo_mem_src(&m_mpoinfo, m_data.data(), m_data.size());
143178
if (!mpo_read_header(&m_mpoinfo))
144179
{
@@ -169,6 +204,9 @@ bool MPOPicture::Decode(uint8_t* pixels,
169204
return false;
170205
}
171206

207+
if (setjmp(s_jpegEscape))
208+
return false;
209+
172210
size_t image = 0;
173211
while (image < m_images)
174212
{

0 commit comments

Comments
 (0)