Skip to content

Commit 4532955

Browse files
authored
Merge pull request #2084 from wmdebrito/fix/mpegts-validate-psi-crc
[mpegts] Validate PSI section CRC32 before parsing PAT/PMT
2 parents c04fbd9 + be978e1 commit 4532955

1 file changed

Lines changed: 44 additions & 0 deletions

File tree

lib/mpegts/mpegts/tsDemuxer.cpp

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -615,6 +615,20 @@ void AVContext::clear_pes(uint16_t channel)
615615
* AVCONTEXT_TS_ERROR
616616
* Parsing error !
617617
*/
618+
// MPEG-2 systems CRC-32 (poly 0x04C11DB7, MSB-first, init 0xFFFFFFFF, no final
619+
// XOR / no reflection). Computing it over a whole PSI section (table_id .. CRC)
620+
// yields 0 when the section is intact.
621+
static uint32_t crc32_mpeg(uint32_t crc, const unsigned char* data, size_t len)
622+
{
623+
for (size_t i = 0; i < len; ++i)
624+
{
625+
crc ^= static_cast<uint32_t>(data[i]) << 24;
626+
for (int b = 0; b < 8; ++b)
627+
crc = (crc & 0x80000000) ? ((crc << 1) ^ 0x04c11db7) : (crc << 1);
628+
}
629+
return crc;
630+
}
631+
618632
int AVContext::parse_ts_psi()
619633
{
620634
size_t len;
@@ -691,6 +705,36 @@ int AVContext::parse_ts_psi()
691705
}
692706

693707
// now entire table is filled
708+
709+
// Validate the section CRC32 before trusting it. Every PSI section (PAT/PMT)
710+
// is protected by a trailing CRC32; random TS payload that merely began with a
711+
// PSI-like table_id will not satisfy it. Without this check such payload is
712+
// misparsed as a PAT/PMT, spuriously (de)registers streams / forces a program
713+
// change, corrupts the demux state and can crash on the next resync. This also
714+
// lets us safely accept a PMT carried on a non-standard PID (issue #2010).
715+
{
716+
const uint16_t section_len = this->packet->packet_table.len;
717+
if (section_len < 4 || section_len > TABLE_BUFFER_SIZE)
718+
return AVCONTEXT_TS_ERROR;
719+
// The 3-byte section header (table_id + syntax/length word) is not kept in
720+
// buf; reconstruct it (PAT/PMT are long syntax sections, top bits '1011').
721+
const unsigned char header[3] = {
722+
this->packet->packet_table.table_id,
723+
static_cast<unsigned char>(0xb0 | ((section_len >> 8) & 0x0f)),
724+
static_cast<unsigned char>(section_len & 0xff)
725+
};
726+
uint32_t crc = 0xffffffff;
727+
crc = crc32_mpeg(crc, header, 3);
728+
crc = crc32_mpeg(crc, this->packet->packet_table.buf, section_len);
729+
if (crc != 0)
730+
{
731+
DBG(DEMUX_DBG_DEBUG, "%s: bad PSI CRC on pid %.4x table_id %.2x; ignoring section\n",
732+
__FUNCTION__, this->packet->pid, this->packet->packet_table.table_id);
733+
this->packet->packet_table.Reset();
734+
return AVCONTEXT_CONTINUE;
735+
}
736+
}
737+
694738
const unsigned char* psi = this->packet->packet_table.buf;
695739
const unsigned char* end_psi = psi + this->packet->packet_table.len;
696740

0 commit comments

Comments
 (0)