summaryrefslogtreecommitdiff
path: root/libavformat/aviobuf.c
diff options
context:
space:
mode:
authorAnton Khirnov <anton@khirnov.net>2016-01-20 11:11:38 +0100
committerAnton Khirnov <anton@khirnov.net>2016-02-22 11:48:30 +0100
commitec4c48397641dbaf4ae8df36c32aaa5a311a11bf (patch)
tree04b1a3187ffa6c4a1821eb5d6dc70ac8397b5006 /libavformat/aviobuf.c
parent8c0ceafb0f25da077ff23e394667119f031574fd (diff)
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.c67
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);