Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
 help / color / mirror / Atom feed
* [FFmpeg-devel] [PATCH] ff-tmp-sanm-unhack (PR #20306)
@ 2025-08-21 17:21 michaelni via ffmpeg-devel
  0 siblings, 0 replies; only message in thread
From: michaelni via ffmpeg-devel @ 2025-08-21 17:21 UTC (permalink / raw)
  To: ffmpeg-devel; +Cc: michaelni

PR #20306 opened by michaelni
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/20306
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/20306.patch

Remove some pointers into freed buffers
Fixes BIGSLEEP-440183164


From fbc1d9dca1aa30ac5e2c63c295652c4b1f54d7be Mon Sep 17 00:00:00 2001
From: Michael Niedermayer <michael@niedermayer.cc>
Date: Thu, 21 Aug 2025 18:40:26 +0200
Subject: [PATCH 1/3] avcodec/sanm: Replace impossible bitstream check by
 assert

the space left and size have already been cross checked by the caller

Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
---
 libavcodec/sanm.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/libavcodec/sanm.c b/libavcodec/sanm.c
index e4308af647..1495da2a1e 100644
--- a/libavcodec/sanm.c
+++ b/libavcodec/sanm.c
@@ -1832,8 +1832,7 @@ static int process_ftch(SANMVideoContext *ctx, int size)
         xoff = bytestream2_get_le16u(&ctx->gb);
         yoff = bytestream2_get_le16u(&ctx->gb);
     } else {
-        if (bytestream2_get_bytes_left(&ctx->gb) < 12)
-            return AVERROR_INVALIDDATA;
+        av_assert0(bytestream2_get_bytes_left(&ctx->gb) >= 12);
         bytestream2_skip(&ctx->gb, 4);
         xoff = bytestream2_get_be32u(&ctx->gb);
         yoff = bytestream2_get_be32u(&ctx->gb);
-- 
2.49.1


From e7b08e87c6f5205bc4c6355ab7138a2ae0a8de17 Mon Sep 17 00:00:00 2001
From: Michael Niedermayer <michael@niedermayer.cc>
Date: Thu, 21 Aug 2025 18:59:36 +0200
Subject: [PATCH 2/3] avcodec/sanm: Remove left/top adjustment hack

Fixes: write after free
Fixes: BIGSLEEP-440183164/process_ftch.anim

Found-by: Google Big Sleep
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
---
 libavcodec/sanm.c | 20 ++++++--------------
 1 file changed, 6 insertions(+), 14 deletions(-)

diff --git a/libavcodec/sanm.c b/libavcodec/sanm.c
index 1495da2a1e..83e0eb7241 100644
--- a/libavcodec/sanm.c
+++ b/libavcodec/sanm.c
@@ -1660,7 +1660,7 @@ static int old_codec48(SANMVideoContext *ctx, int width, int height)
     return 0;
 }
 
-static int process_frame_obj(SANMVideoContext *ctx, GetByteContext *gb)
+static int process_frame_obj(SANMVideoContext *ctx, GetByteContext *gb, int extraleft, int extratop)
 {
     uint16_t w, h, parm2;
     uint8_t codec, param;
@@ -1669,8 +1669,8 @@ static int process_frame_obj(SANMVideoContext *ctx, GetByteContext *gb)
 
     codec = bytestream2_get_byteu(gb);
     param = bytestream2_get_byteu(gb);
-    left  = bytestream2_get_le16u(gb);
-    top   = bytestream2_get_le16u(gb);
+    left  = bytestream2_get_le16u(gb) + extraleft;
+    top   = bytestream2_get_le16u(gb) + extratop;
     w     = bytestream2_get_le16u(gb);
     h     = bytestream2_get_le16u(gb);
     bytestream2_skip(gb, 2);
@@ -1820,7 +1820,7 @@ static int process_frame_obj(SANMVideoContext *ctx, GetByteContext *gb)
 static int process_ftch(SANMVideoContext *ctx, int size)
 {
     uint8_t *sf = ctx->stored_frame;
-    int xoff, yoff, left, top, ret;
+    int xoff, yoff, ret;
     GetByteContext gb;
     uint32_t sz;
 
@@ -1841,18 +1841,10 @@ static int process_ftch(SANMVideoContext *ctx, int size)
     sz = *(uint32_t *)(sf + 0);
     if ((sz > 0) && (sz <= ctx->stored_frame_size - 4)) {
         /* add the FTCH offsets to the left/top values of the stored FOBJ */
-        left = av_le2ne16(*(int16_t *)(sf + 4 + 2));
-        top  = av_le2ne16(*(int16_t *)(sf + 4 + 4));
-        *(int16_t *)(sf + 4 + 2) = av_le2ne16(left + xoff);
-        *(int16_t *)(sf + 4 + 4) = av_le2ne16(top  + yoff);
 
         /* decode the stored FOBJ */
         bytestream2_init(&gb, sf + 4, sz);
-        ret = process_frame_obj(ctx, &gb);
-
-        /* now restore the original left/top values again */
-        *(int16_t *)(sf + 4 + 2) = av_le2ne16(left);
-        *(int16_t *)(sf + 4 + 4) = av_le2ne16(top);
+        ret = process_frame_obj(ctx, &gb, xoff, yoff);
     } else {
         /* this happens a lot in RA1: The individual files are meant to
          * be played in sequence, with some referencing objects STORed
@@ -2359,7 +2351,7 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *frame,
             case MKBETAG('F', 'O', 'B', 'J'):
                 if (size < 16)
                     return AVERROR_INVALIDDATA;
-                if (ret = process_frame_obj(ctx, &ctx->gb))
+                if (ret = process_frame_obj(ctx, &ctx->gb, 0, 0))
                     return ret;
                 have_img = 1;
 
-- 
2.49.1


From 36ca6798358686268093473cbbcb3e706d8ad2c2 Mon Sep 17 00:00:00 2001
From: Michael Niedermayer <michael@niedermayer.cc>
Date: Thu, 21 Aug 2025 19:06:03 +0200
Subject: [PATCH 3/3] avcodec/sanm: Eliminate reference into reallocated frame

AFAIK the original decoder uses the frame buffers in very strange ways
our implementation seems to mimic that and that results in the
bitstream input to point into a frame buffer while code then
parses that and potentially reallocates the frame buffer
leaving pointers hanging into dealllocated space

This simply uses a temporary buffer

Fixes: Writing into freed buffers
Fixes: BIGSLEEP-440183164/old_codec21.anim
Fixes: BIGSLEEP-440183164/old_codec4.anim

Found-by: Google Big Sleep

Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
---
 libavcodec/sanm.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/libavcodec/sanm.c b/libavcodec/sanm.c
index 83e0eb7241..b1a0d05ddc 100644
--- a/libavcodec/sanm.c
+++ b/libavcodec/sanm.c
@@ -1843,8 +1843,13 @@ static int process_ftch(SANMVideoContext *ctx, int size)
         /* add the FTCH offsets to the left/top values of the stored FOBJ */
 
         /* decode the stored FOBJ */
-        bytestream2_init(&gb, sf + 4, sz);
+        uint8_t *bitstream = av_malloc(sz + AV_INPUT_BUFFER_PADDING_SIZE);
+        if (!bitstream)
+            return AVERROR(ENOMEM);
+        memcpy(bitstream, sf + 4, sz);
+        bytestream2_init(&gb, bitstream, sz);
         ret = process_frame_obj(ctx, &gb, xoff, yoff);
+        av_free(bitstream);
     } else {
         /* this happens a lot in RA1: The individual files are meant to
          * be played in sequence, with some referencing objects STORed
-- 
2.49.1

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2025-08-21 17:22 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-08-21 17:21 [FFmpeg-devel] [PATCH] ff-tmp-sanm-unhack (PR #20306) michaelni via ffmpeg-devel

Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

This inbox may be cloned and mirrored by anyone:

	git clone --mirror https://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 ffmpegdev ffmpegdev/ https://master.gitmailbox.com/ffmpegdev \
		ffmpegdev@gitmailbox.com
	public-inbox-index ffmpegdev

Example config snippet for mirrors.


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git