From 386aee6864c5cfc438785d2421b2f056450da014 Mon Sep 17 00:00:00 2001 From: Stefano Sabatini Date: Tue, 20 Dec 2011 13:08:57 +0100 Subject: [PATCH] sink_buffer: copy list of provided formats in the context A list of formats may have been dynamically created by the calling code, and thus should not be referenced by the sink buffer context. Avoid possible invalid data reference. --- libavfilter/formats.c | 26 +++++++++++++++++++++ libavfilter/internal.h | 12 ++++++++++ libavfilter/sink_buffer.c | 49 ++++++++++++++++++++++++++++++--------- 3 files changed, 76 insertions(+), 11 deletions(-) diff --git a/libavfilter/formats.c b/libavfilter/formats.c index ff4d49dd5d..fa2c1be4bb 100644 --- a/libavfilter/formats.c +++ b/libavfilter/formats.c @@ -93,6 +93,32 @@ int ff_fmt_is_in(int fmt, const int *fmts) return 0; } +#define COPY_INT_LIST(list_copy, list, type) { \ + int count = 0; \ + if (list) \ + for (count = 0; list[count] != -1; count++) \ + ; \ + list_copy = av_calloc(count+1, sizeof(type)); \ + if (list_copy) { \ + memcpy(list_copy, list, sizeof(type) * count); \ + list_copy[count] = -1; \ + } \ +} + +int *ff_copy_int_list(const int * const list) +{ + int *ret = NULL; + COPY_INT_LIST(ret, list, int); + return ret; +} + +int64_t *ff_copy_int64_list(const int64_t * const list) +{ + int64_t *ret = NULL; + COPY_INT_LIST(ret, list, int64_t); + return ret; +} + #define MAKE_FORMAT_LIST() \ AVFilterFormats *formats; \ int count = 0; \ diff --git a/libavfilter/internal.h b/libavfilter/internal.h index 9f28a839df..227fe6243d 100644 --- a/libavfilter/internal.h +++ b/libavfilter/internal.h @@ -69,6 +69,18 @@ void ff_avfilter_default_free_buffer(AVFilterBuffer *buf); /** Tell is a format is contained in the provided list terminated by -1. */ int ff_fmt_is_in(int fmt, const int *fmts); +/** + * Return a copy of a list of integers terminated by -1, or NULL in + * case of copy failure. + */ +int *ff_copy_int_list(const int * const list); + +/** + * Return a copy of a list of 64-bit integers, or NULL in case of + * copy failure. + */ +int64_t *ff_copy_int64_list(const int64_t * const list); + /* Functions to parse audio format arguments */ /** diff --git a/libavfilter/sink_buffer.c b/libavfilter/sink_buffer.c index e572385419..926362bef8 100644 --- a/libavfilter/sink_buffer.c +++ b/libavfilter/sink_buffer.c @@ -26,6 +26,7 @@ #include "libavutil/fifo.h" #include "avfilter.h" #include "buffersink.h" +#include "internal.h" AVBufferSinkParams *av_buffersink_params_alloc(void) { @@ -58,12 +59,12 @@ typedef struct { AVFifoBuffer *fifo; ///< FIFO buffer of video frame references /* only used for video */ - const enum PixelFormat *pixel_fmts; ///< list of accepted pixel formats, must be terminated with -1 + enum PixelFormat *pixel_fmts; ///< list of accepted pixel formats, must be terminated with -1 /* only used for audio */ - const enum AVSampleFormat *sample_fmts; ///< list of accepted sample formats, terminated by AV_SAMPLE_FMT_NONE - const int64_t *channel_layouts; ///< list of accepted channel layouts, terminated by -1 - const int *packing_fmts; ///< list of accepted packing formats, terminated by -1 + enum AVSampleFormat *sample_fmts; ///< list of accepted sample formats, terminated by AV_SAMPLE_FMT_NONE + int64_t *channel_layouts; ///< list of accepted channel layouts, terminated by -1 + int *packing_fmts; ///< list of accepted packing formats, terminated by -1 } BufferSinkContext; #define FIFO_INIT_SIZE 8 @@ -169,16 +170,26 @@ static av_cold int vsink_init(AVFilterContext *ctx, const char *args, void *opaq return AVERROR(EINVAL); } else { #if FF_API_OLD_VSINK_API - buf->pixel_fmts = (const enum PixelFormat *)opaque; + const int *pixel_fmts = (const enum PixelFormat *)opaque; #else params = (AVBufferSinkParams *)opaque; - buf->pixel_fmts = params->pixel_fmts; + const int *pixel_fmts = params->pixel_fmts; #endif + buf->pixel_fmts = ff_copy_int_list(pixel_fmts); + if (!buf->pixel_fmts) + return AVERROR(ENOMEM); } return common_init(ctx); } +static av_cold void vsink_uninit(AVFilterContext *ctx) +{ + BufferSinkContext *buf = ctx->priv; + av_freep(&buf->pixel_fmts); + return common_uninit(ctx); +} + static int vsink_query_formats(AVFilterContext *ctx) { BufferSinkContext *buf = ctx->priv; @@ -192,7 +203,7 @@ AVFilter avfilter_vsink_buffersink = { .description = NULL_IF_CONFIG_SMALL("Buffer video frames, and make them available to the end of the filter graph."), .priv_size = sizeof(BufferSinkContext), .init = vsink_init, - .uninit = common_uninit, + .uninit = vsink_uninit, .query_formats = vsink_query_formats, @@ -225,13 +236,29 @@ static av_cold int asink_init(AVFilterContext *ctx, const char *args, void *opaq } else params = (AVABufferSinkParams *)opaque; - buf->sample_fmts = params->sample_fmts; - buf->channel_layouts = params->channel_layouts; - buf->packing_fmts = params->packing_fmts; + buf->sample_fmts = ff_copy_int_list (params->sample_fmts); + buf->channel_layouts = ff_copy_int64_list(params->channel_layouts); + buf->packing_fmts = ff_copy_int_list (params->packing_fmts); + if (!buf->sample_fmts || !buf->channel_layouts || !buf->sample_fmts) { + av_freep(&buf->sample_fmts); + av_freep(&buf->channel_layouts); + av_freep(&buf->packing_fmts); + return AVERROR(ENOMEM); + } return common_init(ctx); } +static av_cold void asink_uninit(AVFilterContext *ctx) +{ + BufferSinkContext *buf = ctx->priv; + + av_freep(&buf->sample_fmts); + av_freep(&buf->channel_layouts); + av_freep(&buf->packing_fmts); + return common_uninit(ctx); +} + static int asink_query_formats(AVFilterContext *ctx) { BufferSinkContext *buf = ctx->priv; @@ -256,7 +283,7 @@ AVFilter avfilter_asink_abuffersink = { .name = "abuffersink", .description = NULL_IF_CONFIG_SMALL("Buffer audio frames, and make them available to the end of the filter graph."), .init = asink_init, - .uninit = common_uninit, + .uninit = asink_uninit, .priv_size = sizeof(BufferSinkContext), .query_formats = asink_query_formats,