avformat/rtmppkt: Check recursion depth

Based on flvdec.c

Fixes: out of array access

Found-by: Xueqing
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
This commit is contained in:
Michael Niedermayer
2026-05-19 17:41:42 +02:00
committed by michaelni
parent 8df8f8b1bb
commit 92804c9e25
+20 -8
View File
@@ -28,6 +28,8 @@
#include "flv.h"
#include "url.h"
#define MAX_DEPTH 16 ///< arbitrary limit to prevent unbounded recursion
void ff_amf_write_bool(uint8_t **dst, int val)
{
bytestream_put_byte(dst, AMF_DATA_TYPE_BOOL);
@@ -437,7 +439,7 @@ void ff_rtmp_packet_destroy(RTMPPacket *pkt)
pkt->size = 0;
}
static int amf_tag_skip(GetByteContext *gb)
static int amf_tag_skip(GetByteContext *gb, int depth)
{
AMFDataType type;
unsigned nb = -1;
@@ -445,6 +447,11 @@ static int amf_tag_skip(GetByteContext *gb)
if (bytestream2_get_bytes_left(gb) < 1)
return -1;
if (depth > MAX_DEPTH) {
av_log(NULL, AV_LOG_ERROR, "amf_tag_skip: exceeded max depth\n");
return AVERROR_PATCHWELCOME;
}
type = bytestream2_get_byte(gb);
switch (type) {
case AMF_DATA_TYPE_NUMBER:
@@ -481,7 +488,7 @@ static int amf_tag_skip(GetByteContext *gb)
return -1;
bytestream2_skip(gb, size);
}
t = amf_tag_skip(gb);
t = amf_tag_skip(gb, depth + 1);
if (t < 0 || bytestream2_get_bytes_left(gb) <= 0)
return -1;
}
@@ -501,7 +508,7 @@ int ff_amf_tag_size(const uint8_t *data, const uint8_t *data_end)
bytestream2_init(&gb, data, data_end - data);
ret = amf_tag_skip(&gb);
ret = amf_tag_skip(&gb, 0);
if (ret < 0 || bytestream2_get_bytes_left(&gb) <= 0)
return -1;
av_assert0(bytestream2_tell(&gb) >= 0 && bytestream2_tell(&gb) <= data_end - data);
@@ -515,7 +522,7 @@ static int amf_get_field_value2(GetByteContext *gb,
int len;
while (bytestream2_peek_byte(gb) != AMF_DATA_TYPE_OBJECT && bytestream2_get_bytes_left(gb) > 0) {
int ret = amf_tag_skip(gb);
int ret = amf_tag_skip(gb, 0);
if (ret < 0)
return -1;
}
@@ -552,7 +559,7 @@ static int amf_get_field_value2(GetByteContext *gb,
}
return 0;
}
len = amf_tag_skip(gb);
len = amf_tag_skip(gb, 0);
if (len < 0 || bytestream2_get_bytes_left(gb) <= 0)
return -1;
}
@@ -595,13 +602,18 @@ static const char* rtmp_packet_type(int type)
}
static void amf_tag_contents(void *ctx, const uint8_t *data,
const uint8_t *data_end)
const uint8_t *data_end, int depth)
{
unsigned int size, nb = -1;
char buf[1024];
AMFDataType type;
int parse_key = 1;
if (depth > MAX_DEPTH) {
av_log(NULL, AV_LOG_ERROR, "amf_tag_contents: exceeded max depth\n");
return;
}
if (data >= data_end)
return;
switch ((type = *data++)) {
@@ -649,7 +661,7 @@ static void amf_tag_contents(void *ctx, const uint8_t *data,
data += size;
av_log(ctx, AV_LOG_DEBUG, " %s: ", buf);
}
amf_tag_contents(ctx, data, data_end);
amf_tag_contents(ctx, data, data_end, depth + 1);
t = ff_amf_tag_size(data, data_end);
if (t < 0 || t >= data_end - data)
return;
@@ -672,7 +684,7 @@ void ff_rtmp_packet_dump(void *ctx, RTMPPacket *p)
uint8_t *src = p->data, *src_end = p->data + p->size;
while (src < src_end) {
int sz;
amf_tag_contents(ctx, src, src_end);
amf_tag_contents(ctx, src, src_end, 0);
sz = ff_amf_tag_size(src, src_end);
if (sz < 0)
break;