修复mp4异常视频尺寸可能导致的未定义行为 (#4785)

libmov 的 `mov_add_video()` 接收 `int` 类型的视频宽高,并直接执行:

  ```c
  track->tkhd.width = width << 16;
  track->tkhd.height = height << 16;
```
这是为了生成 MP4 Track Header 使用的 16.16 定点数。

当输入轨道包含异常视频尺寸,例如负数或在 32 位 int 平台上大于 32767 的值时,左移操作会产生有符号整数溢出,构成未定义行为,可能导致程序异常终止或生成错误的 MP4 轨道信息。
This commit is contained in:
YuLi
2026-07-23 20:21:33 -07:00
committed by GitHub
parent 59ffb2c9fd
commit 1681864d79

View File

@@ -10,6 +10,8 @@
#if defined(ENABLE_MP4) #if defined(ENABLE_MP4)
#include <limits>
#include "MP4Muxer.h" #include "MP4Muxer.h"
#include "Common/config.h" #include "Common/config.h"
@@ -18,6 +20,15 @@ using namespace toolkit;
namespace mediakit { namespace mediakit {
static constexpr int kMaxMovVideoDimension = (std::numeric_limits<int>::max)() >> 16;
static bool isMovVideoDimensionSafe(int width, int height) {
// libmov 将有符号 int 类型的视频宽高左移 16 位写入 16.16 定点数字段,超出此范围会触发未定义行为。
// libmov shifts signed int video dimensions left by 16 for a 16.16 fixed-point field; values outside this range cause undefined behavior.
return width >= 0 && height >= 0 &&
width <= kMaxMovVideoDimension && height <= kMaxMovVideoDimension;
}
MP4Muxer::~MP4Muxer() { MP4Muxer::~MP4Muxer() {
try { try {
closeMP4(); closeMP4();
@@ -182,7 +193,14 @@ bool MP4MuxerInterface::addTrack(const Track::Ptr &track) {
if (track->getTrackType() == TrackVideo) { if (track->getTrackType() == TrackVideo) {
auto video_track = dynamic_pointer_cast<VideoTrack>(track); auto video_track = dynamic_pointer_cast<VideoTrack>(track);
CHECK(video_track); CHECK(video_track);
auto track_id = mp4_writer_add_video(_mov_writter.get(), mp4_object, video_track->getVideoWidth(), video_track->getVideoHeight(), extra_data, extra_size); auto width = video_track->getVideoWidth();
auto height = video_track->getVideoHeight();
if (!isMovVideoDimensionSafe(width, height)) {
WarnL << "Unsafe MP4 video dimensions: " << width << "x" << height
<< ", safe range for each dimension: [0, " << kMaxMovVideoDimension << "]";
return false;
}
auto track_id = mp4_writer_add_video(_mov_writter.get(), mp4_object, width, height, extra_data, extra_size);
if (track_id < 0) { if (track_id < 0) {
WarnL << "mp4_writer_add_video failed: " << video_track->getCodecName(); WarnL << "mp4_writer_add_video failed: " << video_track->getCodecName();
return false; return false;