diff options
author | Michael Niedermayer <michael@niedermayer.cc> | 2025-08-07 19:38:30 +0200 |
---|---|---|
committer | michaelni <michael@niedermayer.cc> | 2025-08-13 10:12:07 +0000 |
commit | d5bdb0b705ce96739e812ca5317361674359369c (patch) | |
tree | d66641913e1a21cab6b6b4666cb9f513a52636c1 | |
parent | 870cfed2317e311a71bc14773332486a162f059c (diff) | |
download | ffmpeg-d5bdb0b705ce96739e812ca5317361674359369c.tar.gz |
avcodec/sanm: Check mv in codec48_block()
Fixes: out of array read
Fixes: 436943287/clusterfuzz-testcase-minimized-ffmpeg_AV_CODEC_ID_SANM_fuzzer-5011037029203968
This issue did oddly enough, not replicate
Found-by: continuous fuzzing process https://github.com/google/oss-fuzz/tree/master/projects/ffmpeg
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
-rw-r--r-- | libavcodec/sanm.c | 28 |
1 files changed, 25 insertions, 3 deletions
diff --git a/libavcodec/sanm.c b/libavcodec/sanm.c index d345f58846..a066a864eb 100644 --- a/libavcodec/sanm.c +++ b/libavcodec/sanm.c @@ -1427,8 +1427,18 @@ static void c48_4to8(uint8_t *dst, const uint8_t *src, const uint16_t w) } } -static int codec48_block(SANMVideoContext *ctx, uint8_t *dst, uint8_t *db, - const uint16_t w) +static int check_mv(int x, int y, const uint16_t w, int h, int blocksize, int mvofs) { + if (mvofs < -x + -y*w) + return AVERROR_INVALIDDATA; + + if (mvofs > w-x-blocksize + w*(h-y-blocksize)) + return AVERROR_INVALIDDATA; + + return 0; +} + +static int codec48_block(SANMVideoContext *ctx, uint8_t *dst, uint8_t *db, int x, int y, + const uint16_t w, int h) { uint8_t opc, sb[16]; int i, j, k, l; @@ -1453,6 +1463,8 @@ static int codec48_block(SANMVideoContext *ctx, uint8_t *dst, uint8_t *db, if (bytestream2_get_bytes_left(&ctx->gb) < 2) return 1; mvofs = bytestream2_get_le16(&ctx->gb); + if (check_mv(x, y, w, h, 8, mvofs)) + return 1; for (i = 0; i < 8; i++) { ofs = w * i; for (k = 0; k < 8; k++) @@ -1480,6 +1492,8 @@ static int codec48_block(SANMVideoContext *ctx, uint8_t *dst, uint8_t *db, for (k = 0; k < 8; k += 4) { opc = bytestream2_get_byteu(&ctx->gb); mvofs = c37_mv[opc * 2] + (c37_mv[opc * 2 + 1] * w); + if (check_mv(x+k, y+i, w, h, 4, mvofs)) + return 1; for (j = 0; j < 4; j++) { ofs = (w * (j + i)) + k; for (l = 0; l < 4; l++) @@ -1494,6 +1508,8 @@ static int codec48_block(SANMVideoContext *ctx, uint8_t *dst, uint8_t *db, for (i = 0; i < 8; i += 4) { for (k = 0; k < 8; k += 4) { mvofs = bytestream2_get_le16(&ctx->gb); + if (check_mv(x+k, y+i, w, h, 4, mvofs)) + return 1; for (j = 0; j < 4; j++) { ofs = (w * (j + i)) + k; for (l = 0; l < 4; l++) @@ -1516,6 +1532,8 @@ static int codec48_block(SANMVideoContext *ctx, uint8_t *dst, uint8_t *db, ofs = (w * i) + j; opc = bytestream2_get_byteu(&ctx->gb); mvofs = c37_mv[opc * 2] + (c37_mv[opc * 2 + 1] * w); + if (check_mv(x+j, y+i, w, h, 2, mvofs)) + return 1; for (l = 0; l < 2; l++) { *(dst + ofs + l + 0) = *(db + ofs + l + 0 + mvofs); *(dst + ofs + l + w) = *(db + ofs + l + w + mvofs); @@ -1530,6 +1548,8 @@ static int codec48_block(SANMVideoContext *ctx, uint8_t *dst, uint8_t *db, for (j = 0; j < 8; j += 2) { ofs = w * i + j; mvofs = bytestream2_get_le16(&ctx->gb); + if (check_mv(x+j, y+i, w, h, 2, mvofs)) + return 1; for (l = 0; l < 2; l++) { *(dst + ofs + l + 0) = *(db + ofs + l + 0 + mvofs); *(dst + ofs + l + w) = *(db + ofs + l + w + mvofs); @@ -1548,6 +1568,8 @@ static int codec48_block(SANMVideoContext *ctx, uint8_t *dst, uint8_t *db, break; default: // copy 8x8 block from prev, c37_mv from source mvofs = c37_mv[opc * 2] + (c37_mv[opc * 2 + 1] * w); + if (check_mv(x, y, w, h, 8, mvofs)) + return 1; for (i = 0; i < 8; i++) { ofs = i * w; for (l = 0; l < 8; l++) @@ -1613,7 +1635,7 @@ static int old_codec48(SANMVideoContext *ctx, int width, int height) if (seq == ctx->prev_seq + 1) { for (j = 0; j < height; j += 8) { for (i = 0; i < width; i += 8) { - if (codec48_block(ctx, dst + i, prev + i, width)) + if (codec48_block(ctx, dst + i, prev + i, i, j, width, height)) return AVERROR_INVALIDDATA; } dst += width * 8; |