On 2/17/2024 10:03 PM, Michael Niedermayer wrote:
On Sat, Feb 17, 2024 at 09:13:21PM -0300, James Almer wrote:


On 2/17/2024 8:48 PM, Michael Niedermayer wrote:
Signed-off-by: Michael Niedermayer <mich...@niedermayer.cc>
---
   Makefile                  |   3 +
   tools/Makefile            |   3 +
   tools/target_sws_fuzzer.c | 168 ++++++++++++++++++++++++++++++++++++++
   3 files changed, 174 insertions(+)
   create mode 100644 tools/target_sws_fuzzer.c

diff --git a/Makefile b/Makefile
index dbc930270b3..b309dbc4db9 100644
--- a/Makefile
+++ b/Makefile
@@ -64,6 +64,9 @@ tools/target_dem_fuzzer$(EXESUF): tools/target_dem_fuzzer.o 
$(FF_DEP_LIBS)
   tools/target_io_dem_fuzzer$(EXESUF): tools/target_io_dem_fuzzer.o 
$(FF_DEP_LIBS)
        $(LD) $(LDFLAGS) $(LDEXEFLAGS) $(LD_O) $^ $(ELIBS) $(FF_EXTRALIBS) 
$(LIBFUZZER_PATH)
+tools/target_sws_fuzzer$(EXESUF): tools/target_sws_fuzzer.o $(FF_DEP_LIBS)
+       $(LD) $(LDFLAGS) $(LDEXEFLAGS) $(LD_O) $^ $(ELIBS) $(FF_EXTRALIBS) 
$(LIBFUZZER_PATH)
+
   tools/enum_options$(EXESUF): ELIBS = $(FF_EXTRALIBS)
   tools/enum_options$(EXESUF): $(FF_DEP_LIBS)
diff --git a/tools/Makefile b/tools/Makefile
index dee6a416688..72e8e709a8d 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -17,6 +17,9 @@ tools/target_dem_fuzzer.o: tools/target_dem_fuzzer.c
   tools/target_io_dem_fuzzer.o: tools/target_dem_fuzzer.c
        $(COMPILE_C) -DIO_FLAT=0
+tools/target_sws_fuzzer.o: tools/target_sws_fuzzer.c
+       $(COMPILE_C)
+
   tools/enc_recon_frame_test$(EXESUF): tools/decode_simple.o
   tools/venc_data_dump$(EXESUF): tools/decode_simple.o
   tools/scale_slice_test$(EXESUF): tools/decode_simple.o
diff --git a/tools/target_sws_fuzzer.c b/tools/target_sws_fuzzer.c
new file mode 100644
index 00000000000..babb6e81629
--- /dev/null
+++ b/tools/target_sws_fuzzer.c
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2024 Michael Niedermayer <michael-ffm...@niedermayer.cc>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "config.h"
+#include "libavutil/avassert.h"
+#include "libavutil/avstring.h"
+#include "libavutil/cpu.h"
+#include "libavutil/imgutils.h"
+#include "libavutil/intreadwrite.h"
+#include "libavutil/opt.h"
+
+#include "libavcodec/bytestream.h"
+
+#include "libswscale/swscale.h"
+
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
+
+static void error(const char *err)
+{
+    fprintf(stderr, "%s", err);
+    exit(1);
+}
+
+static int alloc_plane(uint8_t *data[AV_VIDEO_MAX_PLANES], int 
stride[AV_VIDEO_MAX_PLANES], int w, int h, int format, int *hshift, int *vshift)
+{
+    int ret = av_image_fill_linesizes(stride, format, w);
+    if (ret < 0)
+        return -1;
+
+    av_pix_fmt_get_chroma_sub_sample(format, hshift, vshift);
+
+    for(int p=0; p<AV_VIDEO_MAX_PLANES; p++) {
+        if (stride[p]) {
+            stride[p] = FFALIGN(stride[p], 32);
+            int ph = AV_CEIL_RSHIFT(h, (p == 1 || p == 2) ? *vshift : 0);
+            av_log(0,0, "P:%d St %d ph %d\n", p, stride[p], ph);
+            data[p] = av_mallocz(stride[p] * ph + 32);
+            if (!data[p])
+                return -1;
+        }
+    }
+    if (format == AV_PIX_FMT_PAL8) {
+        data[1] = av_mallocz(256*4);
+        if (!data[1])
+            return -1;
+    }
+    return 0;

av_image_alloc()? Would be better to actually test sws with buffers created
by our own public helpers.

av_image_alloc() allocates the planes in one continous piece
so teh fuzzer would not be able to detect accesses over the end of the first
or accesses prior the 2nd.

So this is not possible

Then use av_image_fill_plane_sizes() after av_image_fill_linesizes() and then allocate the buffers with its output. See fuzz_video_get_buffer() in test_dec_fuzzer.c It's best if we don't rewrite basic buffer allocation and size calculation functions every time we add new code.




+}
+
+static void free_plane(uint8_t *data[AV_VIDEO_MAX_PLANES])
+{
+    for(int p=0; p<AV_VIDEO_MAX_PLANES; p++)
+        av_freep(&data[p]);
+}
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+    int srcW= 48, srcH = 48;
+    int dstW= 48, dstH = 48;
+    int srcHShift, srcVShift;
+    int dstHShift, dstVShift;
+    unsigned flags = 1;
+    int srcStride[AV_VIDEO_MAX_PLANES] = {0};
+    int dstStride[AV_VIDEO_MAX_PLANES] = {0};
+    int ret;
+    const uint8_t *end = data + size;
+    enum AVPixelFormat srcFormat = AV_PIX_FMT_YUV420P;
+    enum AVPixelFormat dstFormat = AV_PIX_FMT_YUV420P;
+    uint8_t *src[4] = { 0 };
+    uint8_t *dst[4] = { 0 };

AV_VIDEO_MAX_PLANES.

will change



+    struct SwsContext *sws = NULL;
+    const AVPixFmtDescriptor *desc_src, *desc_dst;
+
+    if (size > 128) {
+        GetByteContext gbc;
+        int64_t flags64;
+
+        size -= 128;
+        bytestream2_init(&gbc, data + size, 128);
+        srcW = bytestream2_get_le32(&gbc) % 256;
+        srcH = bytestream2_get_le32(&gbc) % 256;
+        dstW = bytestream2_get_le32(&gbc) % 256;
+        dstH = bytestream2_get_le32(&gbc) % 256;
+        flags = bytestream2_get_le32(&gbc);
+
+        srcFormat = bytestream2_get_le32(&gbc) % AV_PIX_FMT_NB;
+        dstFormat = bytestream2_get_le32(&gbc) % AV_PIX_FMT_NB;

nit: Maybe sanitize the choices with sws_isSupportedInput() and
sws_isSupportedOutput()? Unless having sws_init_context() fail with invalid
arguments is also intended.

Honestly i do not know which way is best

Leave it as is, it's not important.




+
+        flags64 = bytestream2_get_le64(&gbc);
+        if (flags64 & 0x10)
+            av_force_cpu_flags(0);
+
+        if (av_image_check_size(srcW, srcH, srcFormat, NULL))
+            srcW = srcH = 123;
+        if (av_image_check_size(dstW, dstH, dstFormat, NULL))
+            dstW = dstH = 123;

Is there a format where this could fail, knowing the dimensions are at most
255x255?

The 255 is temporary, a less restrictive size should be choosen as there may
be bugs with huge sizes. Its just that these really slow it down



+        //TODO alphablend
+    }
+
+    desc_src = av_pix_fmt_desc_get(srcFormat);
+    desc_dst = av_pix_fmt_desc_get(dstFormat);
+
+    ret = alloc_plane(src, srcStride, srcW, srcH, srcFormat, &srcHShift, 
&srcVShift);
+    if (ret < 0)
+        goto end;
+
+    ret = alloc_plane(dst, dstStride, dstW, dstH, dstFormat, &dstHShift, 
&dstVShift);
+    if (ret < 0)
+        goto end;
+
+
+    for(int p=0; p<AV_VIDEO_MAX_PLANES; p++) {
+        int psize = srcStride[p] * AV_CEIL_RSHIFT(srcH, (p == 1 || p == 2) ? 
srcVShift : 0);
+        if (psize > size)
+            psize = size;
+        if (psize) {
+            memcpy(src[p], data, psize);
+            data += psize;
+            size -= psize;
+        }
+    }

av_image_copy(). Or av_image_copy_plane() in a loop if you prefer.

these dont seem to have a input size so ill leave it for now

Ok.


thx

[...]


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

To unsubscribe, visit link above, or email
ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

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

Reply via email to