avformat: add protocol_whitelist

Note to maintainers: update tools

Note to maintainers: set a default whitelist for your protocol
If that makes no sense then consider to set "none" and thus require the user to specify a white-list
for sub-protocols to be opened

Note, testing and checking for missing changes is needed

Reviewed-by: Andreas Cadhalpun <andreas.cadhalpun@googlemail.com>
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
This commit is contained in:
Michael Niedermayer 2016-01-30 02:17:50 +01:00
parent 838abfc1d7
commit 1dba8371d9
10 changed files with 130 additions and 14 deletions

View File

@ -15,6 +15,9 @@ libavutil: 2015-08-28
API changes, most recent first:
2016-02-01 - xxxxxxx - lavf 57.24.100
Add protocol_whitelist to AVFormatContext, AVIOContext
2016-01-31 - xxxxxxx - lavu 55.17.100
Add AV_FRAME_DATA_GOP_TIMECODE for exporting MPEG1/2 GOP timecodes.

View File

@ -1827,6 +1827,13 @@ typedef struct AVFormatContext {
* Demuxing: Set by user.
*/
int (*open_cb)(struct AVFormatContext *s, AVIOContext **p, const char *url, int flags, const AVIOInterruptCB *int_cb, AVDictionary **options);
/**
* ',' separated list of allowed protocols.
* - encoding: unused
* - decoding: set by user through AVOptions (NO direct access)
*/
char *protocol_whitelist;
} AVFormatContext;
int av_format_get_probe_score(const AVFormatContext *s);

View File

@ -73,7 +73,13 @@ static const AVClass *urlcontext_child_class_next(const AVClass *prev)
return NULL;
}
static const AVOption options[] = { { NULL } };
#define OFFSET(x) offsetof(URLContext,x)
#define E AV_OPT_FLAG_ENCODING_PARAM
#define D AV_OPT_FLAG_DECODING_PARAM
static const AVOption options[] = {
{"protocol_whitelist", "List of protocols that are allowed to be used", OFFSET(protocol_whitelist), AV_OPT_TYPE_STRING, { .str = NULL }, CHAR_MIN, CHAR_MAX, D },
{ NULL }
};
const AVClass ffurl_context_class = {
.class_name = "URLContext",
.item_name = urlcontext_to_name,
@ -201,12 +207,43 @@ fail:
int ffurl_connect(URLContext *uc, AVDictionary **options)
{
int err =
int err;
AVDictionary *tmp_opts = NULL;
AVDictionaryEntry *e;
if (!options)
options = &tmp_opts;
// Check that URLContext was initialized correctly and lists are matching if set
av_assert0(!(e=av_dict_get(*options, "protocol_whitelist", NULL, 0)) ||
(uc->protocol_whitelist && !strcmp(uc->protocol_whitelist, e->value)));
if (uc->protocol_whitelist && av_match_list(uc->prot->name, uc->protocol_whitelist, ',') <= 0) {
av_log(uc, AV_LOG_ERROR, "Protocol not on whitelist \'%s\'!\n", uc->protocol_whitelist);
return AVERROR(EINVAL);
}
if (!uc->protocol_whitelist && uc->prot->default_whitelist) {
av_log(uc, AV_LOG_DEBUG, "Setting default whitelist '%s'\n", uc->prot->default_whitelist);
uc->protocol_whitelist = av_strdup(uc->prot->default_whitelist);
if (!uc->protocol_whitelist) {
return AVERROR(ENOMEM);
}
} else if (!uc->protocol_whitelist)
av_log(uc, AV_LOG_DEBUG, "No default whitelist set\n"); // This should be an error once all declare a default whitelist
if ((err = av_dict_set(options, "protocol_whitelist", uc->protocol_whitelist, 0)) < 0)
return err;
err =
uc->prot->url_open2 ? uc->prot->url_open2(uc,
uc->filename,
uc->flags,
options) :
uc->prot->url_open(uc, uc->filename, uc->flags);
av_dict_set(options, "protocol_whitelist", NULL, 0);
if (err)
return err;
uc->is_connected = 1;
@ -296,18 +333,33 @@ int ffurl_alloc(URLContext **puc, const char *filename, int flags,
return AVERROR_PROTOCOL_NOT_FOUND;
}
int ffurl_open(URLContext **puc, const char *filename, int flags,
const AVIOInterruptCB *int_cb, AVDictionary **options)
int ffurl_open_whitelist(URLContext **puc, const char *filename, int flags,
const AVIOInterruptCB *int_cb, AVDictionary **options, const char *whitelist)
{
AVDictionary *tmp_opts = NULL;
AVDictionaryEntry *e;
int ret = ffurl_alloc(puc, filename, flags, int_cb);
if (ret < 0)
return ret;
if (options && (*puc)->prot->priv_data_class &&
(ret = av_opt_set_dict((*puc)->priv_data, options)) < 0)
goto fail;
if (!options)
options = &tmp_opts;
av_assert0(!whitelist ||
!(e=av_dict_get(*options, "protocol_whitelist", NULL, 0)) ||
!strcmp(whitelist, e->value));
if ((ret = av_dict_set(options, "protocol_whitelist", whitelist, 0)) < 0)
goto fail;
if ((ret = av_opt_set_dict(*puc, options)) < 0)
goto fail;
ret = ffurl_connect(*puc, options);
if (!ret)
return 0;
fail:
@ -316,6 +368,13 @@ fail:
return ret;
}
int ffurl_open(URLContext **puc, const char *filename, int flags,
const AVIOInterruptCB *int_cb, AVDictionary **options)
{
return ffurl_open_whitelist(puc, filename, flags,
int_cb, options, NULL);
}
static inline int retry_transfer_wrapper(URLContext *h, uint8_t *buf,
int size, int size_min,
int (*transfer_func)(URLContext *h,

View File

@ -249,6 +249,11 @@ typedef struct AVIOContext {
* This is current internal only, do not use from outside.
*/
int short_seek_threshold;
/**
* ',' separated list of allowed protocols.
*/
const char *protocol_whitelist;
} AVIOContext;
/* unbuffered I/O */

View File

@ -149,6 +149,10 @@ int ffio_fdopen(AVIOContext **s, URLContext *h);
*/
int ffio_open_null_buf(AVIOContext **s);
int ffio_open_whitelist(AVIOContext **s, const char *url, int flags,
const AVIOInterruptCB *int_cb, AVDictionary **options,
const char *whitelist);
/**
* Close a null buffer.
*

View File

@ -53,7 +53,11 @@ static const AVClass *ff_avio_child_class_next(const AVClass *prev)
return prev ? NULL : &ffurl_context_class;
}
#define OFFSET(x) offsetof(AVIOContext,x)
#define E AV_OPT_FLAG_ENCODING_PARAM
#define D AV_OPT_FLAG_DECODING_PARAM
static const AVOption ff_avio_options[] = {
{"protocol_whitelist", "List of protocols that are allowed to be used", OFFSET(protocol_whitelist), AV_OPT_TYPE_STRING, { .str = NULL }, CHAR_MIN, CHAR_MAX, D },
{ NULL },
};
@ -800,6 +804,11 @@ int ffio_fdopen(AVIOContext **s, URLContext *h)
av_free(buffer);
return AVERROR(ENOMEM);
}
(*s)->protocol_whitelist = av_strdup(h->protocol_whitelist);
if (!(*s)->protocol_whitelist && h->protocol_whitelist) {
avio_closep(s);
return AVERROR(ENOMEM);
}
(*s)->direct = h->flags & AVIO_FLAG_DIRECT;
(*s)->seekable = h->is_streamed ? 0 : AVIO_SEEKABLE_NORMAL;
(*s)->max_packet_size = max_packet_size;
@ -919,13 +928,15 @@ int avio_open(AVIOContext **s, const char *filename, int flags)
return avio_open2(s, filename, flags, NULL, NULL);
}
int avio_open2(AVIOContext **s, const char *filename, int flags,
const AVIOInterruptCB *int_cb, AVDictionary **options)
int ffio_open_whitelist(AVIOContext **s, const char *filename, int flags,
const AVIOInterruptCB *int_cb, AVDictionary **options,
const char *whitelist
)
{
URLContext *h;
int err;
err = ffurl_open(&h, filename, flags, int_cb, options);
err = ffurl_open_whitelist(&h, filename, flags, int_cb, options, whitelist);
if (err < 0)
return err;
err = ffio_fdopen(s, h);
@ -936,10 +947,16 @@ int avio_open2(AVIOContext **s, const char *filename, int flags,
return 0;
}
int avio_open2(AVIOContext **s, const char *filename, int flags,
const AVIOInterruptCB *int_cb, AVDictionary **options)
{
return ffio_open_whitelist(s, filename, flags, int_cb, options, NULL);
}
int ffio_open2_wrapper(struct AVFormatContext *s, AVIOContext **pb, const char *url, int flags,
const AVIOInterruptCB *int_cb, AVDictionary **options)
{
return avio_open2(pb, url, flags, int_cb, options);
return ffio_open_whitelist(pb, url, flags, int_cb, options, s->protocol_whitelist);
}
int avio_close(AVIOContext *s)

View File

@ -100,6 +100,7 @@ static const AVOption avformat_options[] = {
{"dump_separator", "set information dump field separator", OFFSET(dump_separator), AV_OPT_TYPE_STRING, {.str = ", "}, CHAR_MIN, CHAR_MAX, D|E},
{"codec_whitelist", "List of decoders that are allowed to be used", OFFSET(codec_whitelist), AV_OPT_TYPE_STRING, { .str = NULL }, CHAR_MIN, CHAR_MAX, D },
{"format_whitelist", "List of demuxers that are allowed to be used", OFFSET(format_whitelist), AV_OPT_TYPE_STRING, { .str = NULL }, CHAR_MIN, CHAR_MAX, D },
{"protocol_whitelist", "List of protocols that are allowed to be used", OFFSET(protocol_whitelist), AV_OPT_TYPE_STRING, { .str = NULL }, CHAR_MIN, CHAR_MAX, D },
{NULL},
};

View File

@ -47,6 +47,7 @@ typedef struct URLContext {
int is_connected;
AVIOInterruptCB interrupt_callback;
int64_t rw_timeout; /**< maximum time to wait for (network) read/write operation completion, in mcs */
const char *protocol_whitelist;
} URLContext;
typedef struct URLProtocol {
@ -94,6 +95,7 @@ typedef struct URLProtocol {
int (*url_close_dir)(URLContext *h);
int (*url_delete)(URLContext *h);
int (*url_move)(URLContext *h_src, URLContext *h_dst);
const char *default_whitelist;
} URLProtocol;
/**
@ -138,6 +140,10 @@ int ffurl_connect(URLContext *uc, AVDictionary **options);
* @return >= 0 in case of success, a negative value corresponding to an
* AVERROR code in case of failure
*/
int ffurl_open_whitelist(URLContext **puc, const char *filename, int flags,
const AVIOInterruptCB *int_cb, AVDictionary **options,
const char *whitelist);
int ffurl_open(URLContext **puc, const char *filename, int flags,
const AVIOInterruptCB *int_cb, AVDictionary **options);

View File

@ -139,11 +139,15 @@ void av_format_inject_global_side_data(AVFormatContext *s)
int ff_copy_whitelists(AVFormatContext *dst, AVFormatContext *src)
{
av_assert0(!dst->codec_whitelist && !dst->format_whitelist);
av_assert0(!dst->codec_whitelist &&
!dst->format_whitelist &&
!dst->protocol_whitelist);
dst-> codec_whitelist = av_strdup(src->codec_whitelist);
dst->format_whitelist = av_strdup(src->format_whitelist);
dst->protocol_whitelist = av_strdup(src->protocol_whitelist);
if ( (src-> codec_whitelist && !dst-> codec_whitelist)
|| (src->format_whitelist && !dst->format_whitelist)) {
|| (src-> format_whitelist && !dst-> format_whitelist)
|| (src->protocol_whitelist && !dst->protocol_whitelist)) {
av_log(dst, AV_LOG_ERROR, "Failed to duplicate whitelist\n");
return AVERROR(ENOMEM);
}
@ -352,9 +356,11 @@ static int init_input(AVFormatContext *s, const char *filename,
(!s->iformat && (s->iformat = av_probe_input_format2(&pd, 0, &score))))
return score;
if ((ret = avio_open2(&s->pb, filename, AVIO_FLAG_READ | s->avio_flags,
&s->interrupt_callback, options)) < 0)
if ((ret = ffio_open_whitelist(&s->pb, filename, AVIO_FLAG_READ | s->avio_flags,
&s->interrupt_callback, options,
s->protocol_whitelist)) < 0)
return ret;
if (s->iformat)
return 0;
return av_probe_input_buffer2(s->pb, &s->iformat, filename,
@ -441,6 +447,14 @@ int avformat_open_input(AVFormatContext **ps, const char *filename,
goto fail;
s->probe_score = ret;
if (!s->protocol_whitelist && s->pb && s->pb->protocol_whitelist) {
s->protocol_whitelist = av_strdup(s->pb->protocol_whitelist);
if (!s->protocol_whitelist) {
ret = AVERROR(ENOMEM);
goto fail;
}
}
if (s->format_whitelist && av_match_list(s->iformat->name, s->format_whitelist, ',') <= 0) {
av_log(s, AV_LOG_ERROR, "Format not on whitelist \'%s\'\n", s->format_whitelist);
ret = AVERROR(EINVAL);

View File

@ -30,8 +30,8 @@
#include "libavutil/version.h"
#define LIBAVFORMAT_VERSION_MAJOR 57
#define LIBAVFORMAT_VERSION_MINOR 23
#define LIBAVFORMAT_VERSION_MICRO 101
#define LIBAVFORMAT_VERSION_MINOR 24
#define LIBAVFORMAT_VERSION_MICRO 100
#define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \
LIBAVFORMAT_VERSION_MINOR, \