diff options
author | Anton Khirnov <anton@khirnov.net> | 2016-01-20 11:11:38 +0100 |
---|---|---|
committer | Anton Khirnov <anton@khirnov.net> | 2016-02-22 11:48:30 +0100 |
commit | ec4c48397641dbaf4ae8df36c32aaa5a311a11bf (patch) | |
tree | 04b1a3187ffa6c4a1821eb5d6dc70ac8397b5006 /libavformat/aviobuf.c | |
parent | 8c0ceafb0f25da077ff23e394667119f031574fd (diff) | |
download | ffmpeg-ec4c48397641dbaf4ae8df36c32aaa5a311a11bf.tar.gz |
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
Diffstat (limited to 'libavformat/aviobuf.c')
-rw-r--r-- | libavformat/aviobuf.c | 67 |
1 files changed, 63 insertions, 4 deletions
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); |