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, \ | |||