[FFmpeg-devel] [PATCH] tools: Add target_sws_fuzzer.c

Michael Niedermayer michael at niedermayer.cc
Sun Feb 18 03:03:21 EET 2024


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 <michael at 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-ffmpeg at 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


> 
> > +}
> > +
> > +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


> 
> > +
> > +        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

thx

[...]
-- 
Michael     GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB

Rewriting code that is poorly written but fully understood is good.
Rewriting code that one doesnt understand is a sign that one is less smart
than the original author, trying to rewrite it will not make it better.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 195 bytes
Desc: not available
URL: <https://ffmpeg.org/pipermail/ffmpeg-devel/attachments/20240218/3b26557f/attachment.sig>


More information about the ffmpeg-devel mailing list