Should make the default behaviour safer for careless callers that open random untrusted files. Bug-Id: CVE-2016-1897 Bug-Id: CVE-2016-1898tags/n3.1
| @@ -13,6 +13,11 @@ libavutil: 2015-08-28 | |||
| API changes, most recent first: | |||
| 2016-xx-xx - xxxxxxx - lavf 57.4.0 - avformat.h | |||
| Add AVFormatContext.protocol_whitelist and protocol_blacklist. | |||
| Add 'protocol_whitelist' and 'protocol_blacklist' private options for | |||
| avio_open2(). | |||
| 2016-xx-xx - lavc 57.13.0 - avcodec.h | |||
| Add AVCodecContext.hw_frames_ctx. | |||
| @@ -1261,6 +1261,24 @@ typedef struct AVFormatContext { | |||
| * A callback for closing the streams opened with AVFormatContext.io_open(). | |||
| */ | |||
| void (*io_close)(struct AVFormatContext *s, AVIOContext *pb); | |||
| /** | |||
| * A comma-separated list of protocol names that will not be used internally | |||
| * by libavformat. If this field is a non-empty string, then protocols | |||
| * listed here will be forbidden. | |||
| * | |||
| * This field should be set using AVOptions. | |||
| */ | |||
| char *protocol_blacklist; | |||
| /** | |||
| * A comma-separated list of protocol names that can be used internally by | |||
| * libavformat. If this field is a non-empty string, all protocols not | |||
| * listed here will be forbidden. | |||
| * | |||
| * This field should be set using AVOptions. | |||
| */ | |||
| char *protocol_whitelist; | |||
| } AVFormatContext; | |||
| typedef struct AVPacketList { | |||
| @@ -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); | |||
| @@ -20,6 +20,7 @@ | |||
| #include "avformat.h" | |||
| #include "avio_internal.h" | |||
| #include "internal.h" | |||
| #include "url.h" | |||
| #include "libavutil/internal.h" | |||
| #include "libavutil/opt.h" | |||
| @@ -93,7 +94,26 @@ static const AVClass av_format_context_class = { | |||
| static int io_open_default(AVFormatContext *s, AVIOContext **pb, | |||
| const char *url, int flags, AVDictionary **options) | |||
| { | |||
| return avio_open2(pb, url, flags, &s->interrupt_callback, options); | |||
| AVDictionary *opts_local = NULL; | |||
| int ret; | |||
| if (!options) | |||
| options = &opts_local; | |||
| if (s->protocol_whitelist) { | |||
| ret = av_dict_set(options, "protocol_whitelist", s->protocol_whitelist, 0); | |||
| if (ret < 0) | |||
| goto finish; | |||
| } | |||
| if (s->protocol_blacklist) { | |||
| ret = av_dict_set(options, "protocol_blacklist", s->protocol_blacklist, 0); | |||
| if (ret < 0) | |||
| goto finish; | |||
| } | |||
| ret = avio_open2(pb, url, flags, &s->interrupt_callback, options); | |||
| finish: | |||
| av_dict_free(&opts_local); | |||
| return ret; | |||
| } | |||
| static void io_close_default(AVFormatContext *s, AVIOContext *pb) | |||
| @@ -70,6 +70,10 @@ static const AVOption avformat_options[] = { | |||
| {"auto", "enabled when required by target format", 0, AV_OPT_TYPE_CONST, {.i64 = AVFMT_AVOID_NEG_TS_AUTO }, INT_MIN, INT_MAX, E, "avoid_negative_ts"}, | |||
| {"make_non_negative", "shift timestamps so they are non negative", 0, AV_OPT_TYPE_CONST, {.i64 = AVFMT_AVOID_NEG_TS_MAKE_NON_NEGATIVE }, INT_MIN, INT_MAX, E, "avoid_negative_ts"}, | |||
| {"make_zero", "shift timestamps so they start at 0", 0, AV_OPT_TYPE_CONST, {.i64 = AVFMT_AVOID_NEG_TS_MAKE_ZERO }, INT_MIN, INT_MAX, E, "avoid_negative_ts"}, | |||
| {"protocol_blacklist", "A comma-separated list of blacklisted protocols used for opening files internally by lavf", | |||
| OFFSET(protocol_blacklist), AV_OPT_TYPE_STRING, { .str = "concat" }, .flags = E | D }, | |||
| {"protocol_whitelist", "A comma-separated list of whitelisted protocols used for opening files internally by lavf", | |||
| OFFSET(protocol_whitelist), AV_OPT_TYPE_STRING, { .str = NULL }, .flags = E | D }, | |||
| {NULL}, | |||
| }; | |||
| @@ -1668,7 +1668,8 @@ int ff_rtsp_connect(AVFormatContext *s) | |||
| return AVERROR(EIO); | |||
| if (!rt->protocols) { | |||
| rt->protocols = ffurl_get_protocols(NULL, NULL); | |||
| rt->protocols = ffurl_get_protocols(s->protocol_whitelist, | |||
| s->protocol_blacklist); | |||
| if (!rt->protocols) | |||
| return AVERROR(ENOMEM); | |||
| } | |||
| @@ -2252,7 +2253,8 @@ static int sdp_read_header(AVFormatContext *s) | |||
| return AVERROR(EIO); | |||
| if (!rt->protocols) { | |||
| rt->protocols = ffurl_get_protocols(NULL, NULL); | |||
| rt->protocols = ffurl_get_protocols(s->protocol_whitelist, | |||
| s->protocol_blacklist); | |||
| if (!rt->protocols) | |||
| return AVERROR(ENOMEM); | |||
| } | |||
| @@ -2379,7 +2381,8 @@ static int rtp_read_header(AVFormatContext *s) | |||
| return AVERROR(EIO); | |||
| if (!rt->protocols) { | |||
| rt->protocols = ffurl_get_protocols(NULL, NULL); | |||
| rt->protocols = ffurl_get_protocols(s->protocol_whitelist, | |||
| s->protocol_blacklist); | |||
| if (!rt->protocols) | |||
| return AVERROR(ENOMEM); | |||
| } | |||
| @@ -640,7 +640,8 @@ static int rtsp_listen(AVFormatContext *s) | |||
| enum RTSPMethod methodcode; | |||
| if (!rt->protocols) { | |||
| rt->protocols = ffurl_get_protocols(NULL, NULL); | |||
| rt->protocols = ffurl_get_protocols(s->protocol_whitelist, | |||
| s->protocol_blacklist); | |||
| if (!rt->protocols) | |||
| return AVERROR(ENOMEM); | |||
| } | |||
| @@ -85,7 +85,8 @@ static int sap_read_header(AVFormatContext *s) | |||
| av_strlcpy(host, "224.2.127.254", sizeof(host)); | |||
| } | |||
| sap->protocols = ffurl_get_protocols(NULL, NULL); | |||
| sap->protocols = ffurl_get_protocols(s->protocol_whitelist, | |||
| s->protocol_blacklist); | |||
| if (!sap->protocols) { | |||
| ret = AVERROR(ENOMEM); | |||
| goto fail; | |||
| @@ -138,7 +138,8 @@ static int sap_write_header(AVFormatContext *s) | |||
| freeaddrinfo(ai); | |||
| } | |||
| sap->protocols = ffurl_get_protocols(NULL, NULL); | |||
| sap->protocols = ffurl_get_protocols(s->protocol_whitelist, | |||
| s->protocol_blacklist); | |||
| if (!sap->protocols) { | |||
| ret = AVERROR(ENOMEM); | |||
| goto fail; | |||
| @@ -312,7 +312,7 @@ static int ism_write_header(AVFormatContext *s) | |||
| goto fail; | |||
| } | |||
| c->protocols = ffurl_get_protocols(NULL, NULL); | |||
| c->protocols = ffurl_get_protocols(s->protocol_whitelist, s->protocol_blacklist); | |||
| if (!c->protocols) { | |||
| ret = AVERROR(ENOMEM); | |||
| goto fail; | |||
| @@ -30,7 +30,7 @@ | |||
| #include "libavutil/version.h" | |||
| #define LIBAVFORMAT_VERSION_MAJOR 57 | |||
| #define LIBAVFORMAT_VERSION_MINOR 3 | |||
| #define LIBAVFORMAT_VERSION_MINOR 4 | |||
| #define LIBAVFORMAT_VERSION_MICRO 0 | |||
| #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \ | |||