diff --git a/README.md b/README.md index 026e69c56..9cb037a28 100755 --- a/README.md +++ b/README.md @@ -146,6 +146,7 @@ For previous versions, please read: ## V3 changes +* v3.0, 2019-12-30, Fix mp4 security issue, check buffer when required size is variable. * v3.0, 2019-12-29, [3.0 alpha7(3.0.90)][r3.0a7] released. 116356 lines. * v3.0, 2019-12-29, For [#1255][bug #1255], support vhost/domain in query string for HTTP streaming. 3.0.90 * v3.0, 2019-12-29, For [#299][bug #299], increase dash segment size for avsync issue. 3.0.89 diff --git a/trunk/src/kernel/srs_kernel_mp4.cpp b/trunk/src/kernel/srs_kernel_mp4.cpp index ac7be290e..d042b11be 100644 --- a/trunk/src/kernel/srs_kernel_mp4.cpp +++ b/trunk/src/kernel/srs_kernel_mp4.cpp @@ -1061,7 +1061,7 @@ SrsMp4TrunEntry::~SrsMp4TrunEntry() { } -int SrsMp4TrunEntry::nb_header() +int SrsMp4TrunEntry::nb_bytes() { int size = 0; @@ -1081,7 +1081,7 @@ int SrsMp4TrunEntry::nb_header() return size; } -srs_error_t SrsMp4TrunEntry::encode_header(SrsBuffer* buf) +srs_error_t SrsMp4TrunEntry::encode(SrsBuffer* buf) { srs_error_t err = srs_success; @@ -1107,7 +1107,7 @@ srs_error_t SrsMp4TrunEntry::encode_header(SrsBuffer* buf) return err; } -srs_error_t SrsMp4TrunEntry::decode_header(SrsBuffer* buf) +srs_error_t SrsMp4TrunEntry::decode(SrsBuffer* buf) { srs_error_t err = srs_success; @@ -1133,7 +1133,7 @@ srs_error_t SrsMp4TrunEntry::decode_header(SrsBuffer* buf) return err; } -stringstream& SrsMp4TrunEntry::dumps_detail(stringstream& ss, SrsMp4DumpContext dc) +stringstream& SrsMp4TrunEntry::dumps(stringstream& ss, SrsMp4DumpContext dc) { if ((owner->flags&SrsMp4TrunFlagsSampleDuration) == SrsMp4TrunFlagsSampleDuration) { ss << "duration=" << sample_duration; @@ -1180,7 +1180,7 @@ int SrsMp4TrackFragmentRunBox::nb_header() vector::iterator it; for (it = entries.begin(); it != entries.end(); ++it) { SrsMp4TrunEntry* entry = *it; - size += entry->nb_header(); + size += entry->nb_bytes(); } return size; @@ -1206,7 +1206,7 @@ srs_error_t SrsMp4TrackFragmentRunBox::encode_header(SrsBuffer* buf) vector::iterator it; for (it = entries.begin(); it != entries.end(); ++it) { SrsMp4TrunEntry* entry = *it; - if ((err = entry->encode_header(buf)) != srs_success) { + if ((err = entry->encode(buf)) != srs_success) { return srs_error_wrap(err, "encode entry"); } } @@ -1234,8 +1234,12 @@ srs_error_t SrsMp4TrackFragmentRunBox::decode_header(SrsBuffer* buf) for (int i = 0; i < (int)sample_count; i++) { SrsMp4TrunEntry* entry = new SrsMp4TrunEntry(this); entries.push_back(entry); + + if (!buf->require(entry->nb_bytes())) { + return srs_error_new(ERROR_MP4_BOX_REQUIRE_SPACE, "trun entry requires %d bytes", entry->nb_bytes()); + } - if ((err = entry->decode_header(buf)) != srs_success) { + if ((err = entry->decode(buf)) != srs_success) { return srs_error_wrap(err, "decode entry"); } } @@ -1259,7 +1263,7 @@ stringstream& SrsMp4TrackFragmentRunBox::dumps_detail(stringstream& ss, SrsMp4Du if (sample_count > 0) { ss << endl; srs_mp4_padding(ss, dc.indent()); - srs_dumps_array(entries, ss, dc.indent(), srs_mp4_pfn_detail2, srs_mp4_delimiter_newline); + srs_dumps_array(entries, ss, dc.indent(), srs_mp4_pfn_box2, srs_mp4_delimiter_newline); } return ss; @@ -2089,13 +2093,22 @@ srs_error_t SrsMp4EditListBox::decode_header(SrsBuffer* buf) SrsMp4ElstEntry& entry = entries[i]; if (version == 1) { + if (!buf->require(16)) { + return srs_error_new(ERROR_MP4_BOX_REQUIRE_SPACE, "no space"); + } entry.segment_duration = buf->read_8bytes(); entry.media_time = buf->read_8bytes(); } else { + if (!buf->require(8)) { + return srs_error_new(ERROR_MP4_BOX_REQUIRE_SPACE, "no space"); + } entry.segment_duration = buf->read_4bytes(); entry.media_time = buf->read_4bytes(); } - + + if (!buf->require(4)) { + return srs_error_new(ERROR_MP4_BOX_REQUIRE_SPACE, "no space"); + } entry.media_rate_integer = buf->read_2bytes(); entry.media_rate_fraction = buf->read_2bytes(); } @@ -3873,7 +3886,7 @@ srs_error_t SrsMp4DecodingTime2SampleBox::on_sample(uint32_t sample_index, SrsMp int SrsMp4DecodingTime2SampleBox::nb_header() { - return SrsMp4FullBox::nb_header() + 4 + 8 * (int)entries.size(); + return SrsMp4FullBox::nb_header() + 4 + 8*(int)entries.size(); } srs_error_t SrsMp4DecodingTime2SampleBox::encode_header(SrsBuffer* buf) @@ -3907,6 +3920,10 @@ srs_error_t SrsMp4DecodingTime2SampleBox::decode_header(SrsBuffer* buf) entries.resize(entry_count); } for (size_t i = 0; i < (size_t)entry_count; i++) { + if (!buf->require(8)) { + return srs_error_new(ERROR_MP4_BOX_REQUIRE_SPACE, "no space"); + } + SrsMp4SttsEntry& entry = entries[i]; entry.sample_count = buf->read_4bytes(); entry.sample_delta = buf->read_4bytes(); @@ -4581,16 +4598,27 @@ srs_error_t SrsMp4SegmentIndexBox::decode_header(SrsBuffer* buf) flags = buf->read_3bytes(); reference_id = buf->read_4bytes(); timescale = buf->read_4bytes(); + if (!version) { + if (!buf->require(8)) { + return srs_error_new(ERROR_MP4_BOX_REQUIRE_SPACE, "no space"); + } earliest_presentation_time = buf->read_4bytes(); first_offset = buf->read_4bytes(); } else { + if (!buf->require(16)) { + return srs_error_new(ERROR_MP4_BOX_REQUIRE_SPACE, "no space"); + } earliest_presentation_time = buf->read_8bytes(); first_offset = buf->read_8bytes(); } uint32_t nn_entries = (uint32_t)(buf->read_4bytes() & 0xffff); for (uint32_t i = 0; i < nn_entries; i++) { + if (!buf->require(12)) { + return srs_error_new(ERROR_MP4_BOX_REQUIRE_SPACE, "no space"); + } + SrsMp4SegmentIndexEntry entry; uint32_t v = buf->read_4bytes(); diff --git a/trunk/src/kernel/srs_kernel_mp4.hpp b/trunk/src/kernel/srs_kernel_mp4.hpp index 725f9dc13..cf63031c3 100644 --- a/trunk/src/kernel/srs_kernel_mp4.hpp +++ b/trunk/src/kernel/srs_kernel_mp4.hpp @@ -186,10 +186,8 @@ public: // An extended type; in this case, the type field is set to ‘uuid’. SrsMp4BoxType type; // For box 'uuid'. - // TODO: FIXME: Should double check buffer. std::vector usertype; protected: - // TODO: FIXME: Should double check buffer. std::vector boxes; private: // The position at buffer to start demux the box. @@ -283,7 +281,6 @@ public: uint32_t minor_version; private: // A list, to the end of the box, of brands - // TODO: FIXME: Should double check buffer. std::vector compatible_brands; public: SrsMp4FileTypeBox(); @@ -478,7 +475,7 @@ enum SrsMp4TrunFlags // Entry for trun. // ISO_IEC_14496-12-base-format-2012.pdf, page 69 -class SrsMp4TrunEntry +class SrsMp4TrunEntry : public ISrsCodec { public: SrsMp4FullBox* owner; @@ -492,10 +489,11 @@ public: SrsMp4TrunEntry(SrsMp4FullBox* o); virtual ~SrsMp4TrunEntry(); - virtual int nb_header(); - virtual srs_error_t encode_header(SrsBuffer* buf); - virtual srs_error_t decode_header(SrsBuffer* buf); - virtual std::stringstream& dumps_detail(std::stringstream& ss, SrsMp4DumpContext dc); + virtual int nb_bytes(); + virtual srs_error_t encode(SrsBuffer* buf); + virtual srs_error_t decode(SrsBuffer* buf); + + virtual std::stringstream& dumps(std::stringstream& ss, SrsMp4DumpContext dc); }; // 8.8.8 Track Fragment Run Box (trun) @@ -516,7 +514,6 @@ public: uint32_t first_sample_flags; // all fields in the following array are optional public: - // TODO: FIXME: Should double check buffer. std::vector entries; public: SrsMp4TrackFragmentRunBox(); @@ -606,7 +603,6 @@ public: class SrsMp4FreeSpaceBox : public SrsMp4Box { private: - // TODO: FIXME: Should double check buffer. std::vector data; public: SrsMp4FreeSpaceBox(SrsMp4BoxType v); @@ -914,7 +910,6 @@ class SrsMp4EditListBox : public SrsMp4FullBox { public: // An integer that gives the number of entries in the following table - // TODO: FIXME: Should double check buffer. std::vector entries; public: SrsMp4EditListBox(); @@ -1165,7 +1160,6 @@ public: class SrsMp4DataReferenceBox : public SrsMp4FullBox { private: - // TODO: FIXME: Should double check buffer. std::vector entries; public: SrsMp4DataReferenceBox(); @@ -1287,7 +1281,6 @@ public: class SrsMp4AvccBox : public SrsMp4Box { public: - // TODO: FIXME: Should double check buffer. std::vector avc_config; public: SrsMp4AvccBox(); @@ -1398,7 +1391,6 @@ class SrsMp4DecoderSpecificInfo : public SrsMp4BaseDescriptor public: // AAC Audio Specific Config. // 1.6.2.1 AudioSpecificConfig, in ISO_IEC_14496-3-AAC-2001.pdf, page 33. - // TODO: FIXME: Should double check buffer. std::vector asc; public: SrsMp4DecoderSpecificInfo(); @@ -1465,7 +1457,6 @@ public: // if (streamDependenceFlag) uint16_t dependsOn_ES_ID; // if (URL_Flag) - // TODO: FIXME: Should double check buffer. std::vector URLstring; // if (OCRstreamFlag) uint16_t OCR_ES_Id; @@ -1511,7 +1502,6 @@ public: class SrsMp4SampleDescriptionBox : public SrsMp4FullBox { private: - // TODO: FIXME: Should double check buffer. std::vector entries; public: SrsMp4SampleDescriptionBox(); @@ -1561,7 +1551,6 @@ class SrsMp4DecodingTime2SampleBox : public SrsMp4FullBox { public: // An integer that gives the number of entries in the following table. - // TODO: FIXME: Should double check buffer. std::vector entries; private: // The index for counter to calc the dts for samples. @@ -1802,7 +1791,6 @@ public: class SrsMp4UserDataBox : public SrsMp4Box { public: - // TODO: FIXME: Should double check buffer. std::vector data; public: SrsMp4UserDataBox(); @@ -1840,7 +1828,6 @@ public: uint32_t timescale; uint64_t earliest_presentation_time; uint64_t first_offset; - // TODO: FIXME: Should double check buffer. std::vector entries; public: SrsMp4SegmentIndexBox(); @@ -2142,6 +2129,7 @@ public: virtual srs_error_t flush(uint64_t& dts); }; +// LCOV_EXCL_START ///////////////////////////////////////////////////////////////////////////////// // MP4 dumps functions. ///////////////////////////////////////////////////////////////////////////////// @@ -2247,5 +2235,7 @@ void srs_mp4_pfn_elem(T& elem, std::stringstream& ss, SrsMp4DumpContext /*dc*/) ss << elem; } +// LCOV_EXCL_STOP + #endif