From: Michael Niedermayer <mich...@niedermayer.cc> TODO: Docs TODO: version bump
Note to maintainers: update tools Note to maintainers: set a default whitelist for your protocol If that makes no sense then consider to set "none" and thus require the user to specify a white-list for sub-protocols to be opened Note, testing and checking for missing changes is needed Signed-off-by: Michael Niedermayer <mich...@niedermayer.cc> --- libavformat/avformat.h | 7 +++++ libavformat/avio.c | 66 ++++++++++++++++++++++++++++++++++++++++--- libavformat/avio_internal.h | 4 +++ libavformat/aviobuf.c | 16 ++++++++--- libavformat/options_table.h | 1 + libavformat/url.h | 6 ++++ libavformat/utils.c | 13 ++++++--- 7 files changed, 101 insertions(+), 12 deletions(-) diff --git a/libavformat/avformat.h b/libavformat/avformat.h index 285bb16..273a6ae 100644 --- a/libavformat/avformat.h +++ b/libavformat/avformat.h @@ -1827,6 +1827,13 @@ typedef struct AVFormatContext { * Demuxing: Set by user. */ int (*open_cb)(struct AVFormatContext *s, AVIOContext **p, const char *url, int flags, const AVIOInterruptCB *int_cb, AVDictionary **options); + + /** + * ',' separated list of allowed protocols. + * - encoding: unused + * - decoding: set by user through AVOptions (NO direct access) + */ + char *protocol_whitelist; } AVFormatContext; int av_format_get_probe_score(const AVFormatContext *s); diff --git a/libavformat/avio.c b/libavformat/avio.c index 05d0557..eb80fc9 100644 --- a/libavformat/avio.c +++ b/libavformat/avio.c @@ -73,7 +73,13 @@ static const AVClass *urlcontext_child_class_next(const AVClass *prev) return NULL; } -static const AVOption options[] = { { NULL } }; +#define OFFSET(x) offsetof(URLContext,x) +#define E AV_OPT_FLAG_ENCODING_PARAM +#define D AV_OPT_FLAG_DECODING_PARAM +static const AVOption options[] = { + {"protocol_whitelist", "List of protocols that are allowed to be used", OFFSET(protocol_whitelist), AV_OPT_TYPE_STRING, { .str = NULL }, CHAR_MIN, CHAR_MAX, D }, + { NULL } +}; const AVClass ffurl_context_class = { .class_name = "URLContext", .item_name = urlcontext_to_name, @@ -201,12 +207,42 @@ fail: int ffurl_connect(URLContext *uc, AVDictionary **options) { - int err = + int err; + AVDictionary *tmp_opts = NULL; + AVDictionaryEntry *e; + + if (!options) + options = &tmp_opts; + + // Check that URLContext was initialized correctly and lists are matching if set + av_assert0(!(e=av_dict_get(*options, "protocol_whitelist", NULL, 0)) || + !strcmp(uc->protocol_whitelist, e->value)); + + if (uc->protocol_whitelist && av_match_list(uc->prot->name, uc->protocol_whitelist, ',') <= 0) { + av_log(uc, AV_LOG_ERROR, "Protocol not on whitelist \'%s\'!\n", uc->protocol_whitelist); + return AVERROR(EINVAL); + } + + if (!uc->protocol_whitelist && uc->prot->default_whitelist) { + uc->protocol_whitelist = av_strdup(uc->prot->default_whitelist); + if (!uc->protocol_whitelist) { + return AVERROR(ENOMEM); + } + } else if (!uc->protocol_whitelist) + av_log(uc, AV_LOG_DEBUG, "No default whitelist set\n"); // This should be an error once all declare a default whitelist + + if ((err = av_dict_set(options, "protocol_whitelist", uc->protocol_whitelist, 0)) < 0) + return err; + + err = uc->prot->url_open2 ? uc->prot->url_open2(uc, uc->filename, uc->flags, options) : uc->prot->url_open(uc, uc->filename, uc->flags); + + av_dict_set(options, "protocol_whitelist", NULL, 0); + if (err) return err; uc->is_connected = 1; @@ -296,18 +332,33 @@ int ffurl_alloc(URLContext **puc, const char *filename, int flags, return AVERROR_PROTOCOL_NOT_FOUND; } -int ffurl_open(URLContext **puc, const char *filename, int flags, - const AVIOInterruptCB *int_cb, AVDictionary **options) +int ffurl_open_whitelist(URLContext **puc, const char *filename, int flags, + const AVIOInterruptCB *int_cb, AVDictionary **options, const char *whitelist) { + AVDictionary *tmp_opts = NULL; + AVDictionaryEntry *e; int ret = ffurl_alloc(puc, filename, flags, int_cb); if (ret < 0) return ret; if (options && (*puc)->prot->priv_data_class && (ret = av_opt_set_dict((*puc)->priv_data, options)) < 0) goto fail; + + if (!options) + options = &tmp_opts; + + av_assert0(!whitelist || + !(e=av_dict_get(*options, "protocol_whitelist", NULL, 0)) || + !strcmp(whitelist, e->value)); + + if ((ret = av_dict_set(options, "protocol_whitelist", whitelist, 0)) < 0) + goto fail; + if ((ret = av_opt_set_dict(*puc, options)) < 0) goto fail; + ret = ffurl_connect(*puc, options); + if (!ret) return 0; fail: @@ -316,6 +367,13 @@ fail: return ret; } +int ffurl_open(URLContext **puc, const char *filename, int flags, + const AVIOInterruptCB *int_cb, AVDictionary **options) +{ + return ffurl_open_whitelist(puc, filename, flags, + int_cb, options, NULL); +} + static inline int retry_transfer_wrapper(URLContext *h, uint8_t *buf, int size, int size_min, int (*transfer_func)(URLContext *h, diff --git a/libavformat/avio_internal.h b/libavformat/avio_internal.h index ad50567..f7c8588 100644 --- a/libavformat/avio_internal.h +++ b/libavformat/avio_internal.h @@ -149,6 +149,10 @@ int ffio_fdopen(AVIOContext **s, URLContext *h); */ int ffio_open_null_buf(AVIOContext **s); +int ffio_open_whitelist(AVIOContext **s, const char *url, int flags, + const AVIOInterruptCB *int_cb, AVDictionary **options, + const char *whitelist); + /** * Close a null buffer. * diff --git a/libavformat/aviobuf.c b/libavformat/aviobuf.c index b56d113..234b2cc 100644 --- a/libavformat/aviobuf.c +++ b/libavformat/aviobuf.c @@ -919,13 +919,15 @@ int avio_open(AVIOContext **s, const char *filename, int flags) return avio_open2(s, filename, flags, NULL, NULL); } -int avio_open2(AVIOContext **s, const char *filename, int flags, - const AVIOInterruptCB *int_cb, AVDictionary **options) +int ffio_open_whitelist(AVIOContext **s, const char *filename, int flags, + const AVIOInterruptCB *int_cb, AVDictionary **options, + const char *whitelist + ) { URLContext *h; int err; - err = ffurl_open(&h, filename, flags, int_cb, options); + err = ffurl_open_whitelist(&h, filename, flags, int_cb, options, whitelist); if (err < 0) return err; err = ffio_fdopen(s, h); @@ -936,10 +938,16 @@ int avio_open2(AVIOContext **s, const char *filename, int flags, return 0; } +int avio_open2(AVIOContext **s, const char *filename, int flags, + const AVIOInterruptCB *int_cb, AVDictionary **options) +{ + return ffio_open_whitelist(s, filename, flags, int_cb, options, NULL); +} + int ffio_open2_wrapper(struct AVFormatContext *s, AVIOContext **pb, const char *url, int flags, const AVIOInterruptCB *int_cb, AVDictionary **options) { - return avio_open2(pb, url, flags, int_cb, options); + return ffio_open_whitelist(pb, url, flags, int_cb, options, s->protocol_whitelist); } int avio_close(AVIOContext *s) diff --git a/libavformat/options_table.h b/libavformat/options_table.h index cc64bea..8926fe5 100644 --- a/libavformat/options_table.h +++ b/libavformat/options_table.h @@ -100,6 +100,7 @@ static const AVOption avformat_options[] = { {"dump_separator", "set information dump field separator", OFFSET(dump_separator), AV_OPT_TYPE_STRING, {.str = ", "}, CHAR_MIN, CHAR_MAX, D|E}, {"codec_whitelist", "List of decoders that are allowed to be used", OFFSET(codec_whitelist), AV_OPT_TYPE_STRING, { .str = NULL }, CHAR_MIN, CHAR_MAX, D }, {"format_whitelist", "List of demuxers that are allowed to be used", OFFSET(format_whitelist), AV_OPT_TYPE_STRING, { .str = NULL }, CHAR_MIN, CHAR_MAX, D }, +{"protocol_whitelist", "List of protocols that are allowed to be used", OFFSET(protocol_whitelist), AV_OPT_TYPE_STRING, { .str = NULL }, CHAR_MIN, CHAR_MAX, D }, {NULL}, }; diff --git a/libavformat/url.h b/libavformat/url.h index 391e3bc..5c3f3fb 100644 --- a/libavformat/url.h +++ b/libavformat/url.h @@ -47,6 +47,7 @@ typedef struct URLContext { int is_connected; AVIOInterruptCB interrupt_callback; int64_t rw_timeout; /**< maximum time to wait for (network) read/write operation completion, in mcs */ + char *protocol_whitelist; } URLContext; typedef struct URLProtocol { @@ -94,6 +95,7 @@ typedef struct URLProtocol { int (*url_close_dir)(URLContext *h); int (*url_delete)(URLContext *h); int (*url_move)(URLContext *h_src, URLContext *h_dst); + char *default_whitelist; } URLProtocol; /** @@ -138,6 +140,10 @@ int ffurl_connect(URLContext *uc, AVDictionary **options); * @return >= 0 in case of success, a negative value corresponding to an * AVERROR code in case of failure */ +int ffurl_open_whitelist(URLContext **puc, const char *filename, int flags, + const AVIOInterruptCB *int_cb, AVDictionary **options, + const char *whitelist); + int ffurl_open(URLContext **puc, const char *filename, int flags, const AVIOInterruptCB *int_cb, AVDictionary **options); diff --git a/libavformat/utils.c b/libavformat/utils.c index 6bf2fd1..786a209 100644 --- a/libavformat/utils.c +++ b/libavformat/utils.c @@ -139,11 +139,15 @@ void av_format_inject_global_side_data(AVFormatContext *s) int ff_copy_whitelists(AVFormatContext *dst, AVFormatContext *src) { - av_assert0(!dst->codec_whitelist && !dst->format_whitelist); + av_assert0(!dst->codec_whitelist && + !dst->format_whitelist && + !dst->protocol_whitelist); dst-> codec_whitelist = av_strdup(src->codec_whitelist); dst->format_whitelist = av_strdup(src->format_whitelist); + dst->protocol_whitelist = av_strdup(src->protocol_whitelist); if ( (src-> codec_whitelist && !dst-> codec_whitelist) - || (src->format_whitelist && !dst->format_whitelist)) { + || (src-> format_whitelist && !dst-> format_whitelist) + || (src->protocol_whitelist && !dst->protocol_whitelist)) { av_log(dst, AV_LOG_ERROR, "Failed to duplicate whitelist\n"); return AVERROR(ENOMEM); } @@ -352,8 +356,9 @@ static int init_input(AVFormatContext *s, const char *filename, (!s->iformat && (s->iformat = av_probe_input_format2(&pd, 0, &score)))) return score; - if ((ret = avio_open2(&s->pb, filename, AVIO_FLAG_READ | s->avio_flags, - &s->interrupt_callback, options)) < 0) + if ((ret = ffio_open_whitelist(&s->pb, filename, AVIO_FLAG_READ | s->avio_flags, + &s->interrupt_callback, options, + s->protocol_whitelist)) < 0) return ret; if (s->iformat) return 0; -- 1.7.9.5 _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel