mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2024-11-26 19:01:44 +02:00
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
This commit is contained in:
parent
8c0ceafb0f
commit
ec4c483976
@ -13,6 +13,11 @@ libavutil: 2015-08-28
|
|||||||
|
|
||||||
API changes, most recent first:
|
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
|
2016-xx-xx - lavc 57.13.0 - avcodec.h
|
||||||
Add AVCodecContext.hw_frames_ctx.
|
Add AVCodecContext.hw_frames_ctx.
|
||||||
|
|
||||||
|
@ -1261,6 +1261,24 @@ typedef struct AVFormatContext {
|
|||||||
* A callback for closing the streams opened with AVFormatContext.io_open().
|
* A callback for closing the streams opened with AVFormatContext.io_open().
|
||||||
*/
|
*/
|
||||||
void (*io_close)(struct AVFormatContext *s, AVIOContext *pb);
|
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;
|
} AVFormatContext;
|
||||||
|
|
||||||
typedef struct AVPacketList {
|
typedef struct AVPacketList {
|
||||||
|
@ -41,20 +41,53 @@
|
|||||||
#define SHORT_SEEK_THRESHOLD 4096
|
#define SHORT_SEEK_THRESHOLD 4096
|
||||||
|
|
||||||
typedef struct AVIOInternal {
|
typedef struct AVIOInternal {
|
||||||
|
const AVClass *class;
|
||||||
|
|
||||||
|
char *protocol_whitelist;
|
||||||
|
char *protocol_blacklist;
|
||||||
|
|
||||||
URLContext *h;
|
URLContext *h;
|
||||||
const URLProtocol **protocols;
|
const URLProtocol **protocols;
|
||||||
} AVIOInternal;
|
} 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)
|
static void *ff_avio_child_next(void *obj, void *prev)
|
||||||
{
|
{
|
||||||
AVIOContext *s = obj;
|
AVIOContext *s = obj;
|
||||||
AVIOInternal *internal = s->opaque;
|
return prev ? NULL : s->opaque;
|
||||||
return prev ? NULL : internal->h;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const AVClass *ff_avio_child_class_next(const AVClass *prev)
|
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[] = {
|
static const AVOption ff_avio_options[] = {
|
||||||
@ -750,8 +783,11 @@ int ffio_fdopen(AVIOContext **s, URLContext *h)
|
|||||||
if (!internal)
|
if (!internal)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
|
internal->class = &io_priv_class;
|
||||||
internal->h = h;
|
internal->h = h;
|
||||||
|
|
||||||
|
av_opt_set_defaults(internal);
|
||||||
|
|
||||||
*s = avio_alloc_context(buffer, buffer_size, h->flags & AVIO_FLAG_WRITE,
|
*s = avio_alloc_context(buffer, buffer_size, h->flags & AVIO_FLAG_WRITE,
|
||||||
internal, io_read_packet, io_write_packet, io_seek);
|
internal, io_read_packet, io_write_packet, io_seek);
|
||||||
if (!*s)
|
if (!*s)
|
||||||
@ -766,6 +802,8 @@ int ffio_fdopen(AVIOContext **s, URLContext *h)
|
|||||||
(*s)->av_class = &ff_avio_class;
|
(*s)->av_class = &ff_avio_class;
|
||||||
return 0;
|
return 0;
|
||||||
fail:
|
fail:
|
||||||
|
if (internal)
|
||||||
|
av_opt_free(internal);
|
||||||
av_freep(&internal);
|
av_freep(&internal);
|
||||||
av_freep(&buffer);
|
av_freep(&buffer);
|
||||||
return AVERROR(ENOMEM);
|
return AVERROR(ENOMEM);
|
||||||
@ -849,10 +887,21 @@ int avio_open2(AVIOContext **s, const char *filename, int flags,
|
|||||||
{
|
{
|
||||||
AVIOInternal *internal;
|
AVIOInternal *internal;
|
||||||
const URLProtocol **protocols;
|
const URLProtocol **protocols;
|
||||||
|
char *proto_whitelist = NULL, *proto_blacklist = NULL;
|
||||||
|
AVDictionaryEntry *e;
|
||||||
URLContext *h;
|
URLContext *h;
|
||||||
int err;
|
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)
|
if (!protocols)
|
||||||
return AVERROR(ENOMEM);
|
return AVERROR(ENOMEM);
|
||||||
|
|
||||||
@ -872,6 +921,14 @@ int avio_open2(AVIOContext **s, const char *filename, int flags,
|
|||||||
internal = (*s)->opaque;
|
internal = (*s)->opaque;
|
||||||
internal->protocols = protocols;
|
internal->protocols = protocols;
|
||||||
|
|
||||||
|
if (options) {
|
||||||
|
err = av_opt_set_dict(internal, options);
|
||||||
|
if (err < 0) {
|
||||||
|
avio_closep(s);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -887,6 +944,8 @@ int avio_close(AVIOContext *s)
|
|||||||
internal = s->opaque;
|
internal = s->opaque;
|
||||||
h = internal->h;
|
h = internal->h;
|
||||||
|
|
||||||
|
av_opt_free(internal);
|
||||||
|
|
||||||
av_freep(&internal->protocols);
|
av_freep(&internal->protocols);
|
||||||
av_freep(&s->opaque);
|
av_freep(&s->opaque);
|
||||||
av_freep(&s->buffer);
|
av_freep(&s->buffer);
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
#include "avformat.h"
|
#include "avformat.h"
|
||||||
#include "avio_internal.h"
|
#include "avio_internal.h"
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
|
#include "url.h"
|
||||||
|
|
||||||
#include "libavutil/internal.h"
|
#include "libavutil/internal.h"
|
||||||
#include "libavutil/opt.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,
|
static int io_open_default(AVFormatContext *s, AVIOContext **pb,
|
||||||
const char *url, int flags, AVDictionary **options)
|
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)
|
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"},
|
{"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_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"},
|
{"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},
|
{NULL},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1668,7 +1668,8 @@ int ff_rtsp_connect(AVFormatContext *s)
|
|||||||
return AVERROR(EIO);
|
return AVERROR(EIO);
|
||||||
|
|
||||||
if (!rt->protocols) {
|
if (!rt->protocols) {
|
||||||
rt->protocols = ffurl_get_protocols(NULL, NULL);
|
rt->protocols = ffurl_get_protocols(s->protocol_whitelist,
|
||||||
|
s->protocol_blacklist);
|
||||||
if (!rt->protocols)
|
if (!rt->protocols)
|
||||||
return AVERROR(ENOMEM);
|
return AVERROR(ENOMEM);
|
||||||
}
|
}
|
||||||
@ -2252,7 +2253,8 @@ static int sdp_read_header(AVFormatContext *s)
|
|||||||
return AVERROR(EIO);
|
return AVERROR(EIO);
|
||||||
|
|
||||||
if (!rt->protocols) {
|
if (!rt->protocols) {
|
||||||
rt->protocols = ffurl_get_protocols(NULL, NULL);
|
rt->protocols = ffurl_get_protocols(s->protocol_whitelist,
|
||||||
|
s->protocol_blacklist);
|
||||||
if (!rt->protocols)
|
if (!rt->protocols)
|
||||||
return AVERROR(ENOMEM);
|
return AVERROR(ENOMEM);
|
||||||
}
|
}
|
||||||
@ -2379,7 +2381,8 @@ static int rtp_read_header(AVFormatContext *s)
|
|||||||
return AVERROR(EIO);
|
return AVERROR(EIO);
|
||||||
|
|
||||||
if (!rt->protocols) {
|
if (!rt->protocols) {
|
||||||
rt->protocols = ffurl_get_protocols(NULL, NULL);
|
rt->protocols = ffurl_get_protocols(s->protocol_whitelist,
|
||||||
|
s->protocol_blacklist);
|
||||||
if (!rt->protocols)
|
if (!rt->protocols)
|
||||||
return AVERROR(ENOMEM);
|
return AVERROR(ENOMEM);
|
||||||
}
|
}
|
||||||
|
@ -640,7 +640,8 @@ static int rtsp_listen(AVFormatContext *s)
|
|||||||
enum RTSPMethod methodcode;
|
enum RTSPMethod methodcode;
|
||||||
|
|
||||||
if (!rt->protocols) {
|
if (!rt->protocols) {
|
||||||
rt->protocols = ffurl_get_protocols(NULL, NULL);
|
rt->protocols = ffurl_get_protocols(s->protocol_whitelist,
|
||||||
|
s->protocol_blacklist);
|
||||||
if (!rt->protocols)
|
if (!rt->protocols)
|
||||||
return AVERROR(ENOMEM);
|
return AVERROR(ENOMEM);
|
||||||
}
|
}
|
||||||
|
@ -85,7 +85,8 @@ static int sap_read_header(AVFormatContext *s)
|
|||||||
av_strlcpy(host, "224.2.127.254", sizeof(host));
|
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) {
|
if (!sap->protocols) {
|
||||||
ret = AVERROR(ENOMEM);
|
ret = AVERROR(ENOMEM);
|
||||||
goto fail;
|
goto fail;
|
||||||
|
@ -138,7 +138,8 @@ static int sap_write_header(AVFormatContext *s)
|
|||||||
freeaddrinfo(ai);
|
freeaddrinfo(ai);
|
||||||
}
|
}
|
||||||
|
|
||||||
sap->protocols = ffurl_get_protocols(NULL, NULL);
|
sap->protocols = ffurl_get_protocols(s->protocol_whitelist,
|
||||||
|
s->protocol_blacklist);
|
||||||
if (!sap->protocols) {
|
if (!sap->protocols) {
|
||||||
ret = AVERROR(ENOMEM);
|
ret = AVERROR(ENOMEM);
|
||||||
goto fail;
|
goto fail;
|
||||||
|
@ -312,7 +312,7 @@ static int ism_write_header(AVFormatContext *s)
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
c->protocols = ffurl_get_protocols(NULL, NULL);
|
c->protocols = ffurl_get_protocols(s->protocol_whitelist, s->protocol_blacklist);
|
||||||
if (!c->protocols) {
|
if (!c->protocols) {
|
||||||
ret = AVERROR(ENOMEM);
|
ret = AVERROR(ENOMEM);
|
||||||
goto fail;
|
goto fail;
|
||||||
|
@ -30,7 +30,7 @@
|
|||||||
#include "libavutil/version.h"
|
#include "libavutil/version.h"
|
||||||
|
|
||||||
#define LIBAVFORMAT_VERSION_MAJOR 57
|
#define LIBAVFORMAT_VERSION_MAJOR 57
|
||||||
#define LIBAVFORMAT_VERSION_MINOR 3
|
#define LIBAVFORMAT_VERSION_MINOR 4
|
||||||
#define LIBAVFORMAT_VERSION_MICRO 0
|
#define LIBAVFORMAT_VERSION_MICRO 0
|
||||||
|
|
||||||
#define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \
|
#define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \
|
||||||
|
Loading…
Reference in New Issue
Block a user