From ec4c48397641dbaf4ae8df36c32aaa5a311a11bf Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Wed, 20 Jan 2016 11:11:38 +0100 Subject: lavf: add a protocol whitelist/blacklist for file opened internally Should make the default behaviour safer for careless callers that open random untrusted files. Bug-Id: CVE-2016-1897 Bug-Id: CVE-2016-1898 --- libavformat/aviobuf.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 63 insertions(+), 4 deletions(-) (limited to 'libavformat/aviobuf.c') diff --git a/libavformat/aviobuf.c b/libavformat/aviobuf.c index 20bef66029..a2edb74974 100644 --- a/libavformat/aviobuf.c +++ b/libavformat/aviobuf.c @@ -41,20 +41,53 @@ #define SHORT_SEEK_THRESHOLD 4096 typedef struct AVIOInternal { + const AVClass *class; + + char *protocol_whitelist; + char *protocol_blacklist; + URLContext *h; const URLProtocol **protocols; } AVIOInternal; +static void *io_priv_child_next(void *obj, void *prev) +{ + AVIOInternal *internal = obj; + return prev ? NULL : internal->h; +} + +static const AVClass *io_priv_child_class_next(const AVClass *prev) +{ + return prev ? NULL : &ffurl_context_class; +} + +#define OFFSET(x) offsetof(AVIOInternal, x) +static const AVOption io_priv_options[] = { + { "protocol_whitelist", "A comma-separated list of allowed protocols", + OFFSET(protocol_whitelist), AV_OPT_TYPE_STRING }, + { "protocol_blacklist", "A comma-separated list of forbidden protocols", + OFFSET(protocol_whitelist), AV_OPT_TYPE_STRING }, + { NULL }, +}; + +static const AVClass io_priv_class = { + .class_name = "AVIOContext", + .item_name = av_default_item_name, + .version = LIBAVUTIL_VERSION_INT, + .option = io_priv_options, + .child_next = io_priv_child_next, + .child_class_next = io_priv_child_class_next, +}; + static void *ff_avio_child_next(void *obj, void *prev) { AVIOContext *s = obj; - AVIOInternal *internal = s->opaque; - return prev ? NULL : internal->h; + return prev ? NULL : s->opaque; } static const AVClass *ff_avio_child_class_next(const AVClass *prev) { - return prev ? NULL : &ffurl_context_class; + return prev ? NULL : &io_priv_class; } static const AVOption ff_avio_options[] = { @@ -750,8 +783,11 @@ int ffio_fdopen(AVIOContext **s, URLContext *h) if (!internal) goto fail; + internal->class = &io_priv_class; internal->h = h; + av_opt_set_defaults(internal); + *s = avio_alloc_context(buffer, buffer_size, h->flags & AVIO_FLAG_WRITE, internal, io_read_packet, io_write_packet, io_seek); if (!*s) @@ -766,6 +802,8 @@ int ffio_fdopen(AVIOContext **s, URLContext *h) (*s)->av_class = &ff_avio_class; return 0; fail: + if (internal) + av_opt_free(internal); av_freep(&internal); av_freep(&buffer); return AVERROR(ENOMEM); @@ -849,10 +887,21 @@ int avio_open2(AVIOContext **s, const char *filename, int flags, { AVIOInternal *internal; const URLProtocol **protocols; + char *proto_whitelist = NULL, *proto_blacklist = NULL; + AVDictionaryEntry *e; URLContext *h; int err; - protocols = ffurl_get_protocols(NULL, NULL); + if (options) { + e = av_dict_get(*options, "protocol_whitelist", NULL, 0); + if (e) + proto_whitelist = e->value; + e = av_dict_get(*options, "protocol_blacklist", NULL, 0); + if (e) + proto_blacklist = e->value; + } + + protocols = ffurl_get_protocols(proto_whitelist, proto_blacklist); if (!protocols) return AVERROR(ENOMEM); @@ -872,6 +921,14 @@ int avio_open2(AVIOContext **s, const char *filename, int flags, internal = (*s)->opaque; internal->protocols = protocols; + if (options) { + err = av_opt_set_dict(internal, options); + if (err < 0) { + avio_closep(s); + return err; + } + } + return 0; } @@ -887,6 +944,8 @@ int avio_close(AVIOContext *s) internal = s->opaque; h = internal->h; + av_opt_free(internal); + av_freep(&internal->protocols); av_freep(&s->opaque); av_freep(&s->buffer); -- cgit v1.2.3