Should make the default behaviour safer for careless callers that open random untrusted files.
Unified · Split
| @@ -13,6 +13,11 @@ libavutil: 2015-08-28 · 12 unmodified lines | ||
| 13 | 13 | |
| 14 | 14 | API changes, most recent first: |
| 15 | 15 | |
| 16 | +2016-xx-xx - xxxxxxx - lavf 57.4.0 - avformat.h | |
| 17 | + Add AVFormatContext.protocol_whitelist and protocol_blacklist. | |
| 18 | + Add 'protocol_whitelist' and 'protocol_blacklist' private options for | |
| 19 | + avio_open2(). | |
| 20 | + | |
| 16 | 21 | 2016-xx-xx - lavc 57.13.0 - avcodec.h |
| 17 | 22 | Add AVCodecContext.hw_frames_ctx. |
| 18 | 23 | |
| @@ -1261,6 +1261,24 @@ typedef struct AVFormatContext { · 1260 unmodified lines | ||
| 1261 | 1261 | * A callback for closing the streams opened with AVFormatContext.io_open(). |
| 1262 | 1262 | */ |
| 1263 | 1263 | void (*io_close)(struct AVFormatContext *s, AVIOContext *pb); |
| 1264 | + | |
| 1265 | + /** | |
| 1266 | + * A comma-separated list of protocol names that will not be used internally | |
| 1267 | + * by libavformat. If this field is a non-empty string, then protocols | |
| 1268 | + * listed here will be forbidden. | |
| 1269 | + * | |
| 1270 | + * This field should be set using AVOptions. | |
| 1271 | + */ | |
| 1272 | + char *protocol_blacklist; | |
| 1273 | + | |
| 1274 | + /** | |
| 1275 | + * A comma-separated list of protocol names that can be used internally by | |
| 1276 | + * libavformat. If this field is a non-empty string, all protocols not | |
| 1277 | + * listed here will be forbidden. | |
| 1278 | + * | |
| 1279 | + * This field should be set using AVOptions. | |
| 1280 | + */ | |
| 1281 | + char *protocol_whitelist; | |
| 1264 | 1282 | } AVFormatContext; |
| 1265 | 1283 | |
| 1266 | 1284 | typedef struct AVPacketList { |
| @@ -41,20 +41,53 @@ · 40 unmodified lines | ||
| 41 | 41 | #define SHORT_SEEK_THRESHOLD 4096 |
| 42 | 42 | |
| 43 | 43 | typedef struct AVIOInternal { |
| 44 | + const AVClass *class; | |
| 45 | + | |
| 46 | + char *protocol_whitelist; | |
| 47 | + char *protocol_blacklist; | |
| 48 | + | |
| 44 | 49 | URLContext *h; |
| 45 | 50 | const URLProtocol **protocols; |
| 46 | 51 | } AVIOInternal; |
| 47 | 52 | |
| 53 | +static void *io_priv_child_next(void *obj, void *prev) | |
| 54 | +{ | |
| 55 | + AVIOInternal *internal = obj; | |
| 56 | + return prev ? NULL : internal->h; | |
| 57 | +} | |
| 58 | + | |
| 59 | +static const AVClass *io_priv_child_class_next(const AVClass *prev) | |
| 60 | +{ | |
| 61 | + return prev ? NULL : &ffurl_context_class; | |
| 62 | +} | |
| 63 | + | |
| 64 | +#define OFFSET(x) offsetof(AVIOInternal, x) | |
| 65 | +static const AVOption io_priv_options[] = { | |
| 66 | + { "protocol_whitelist", "A comma-separated list of allowed protocols", | |
| 67 | + OFFSET(protocol_whitelist), AV_OPT_TYPE_STRING }, | |
| 68 | + { "protocol_blacklist", "A comma-separated list of forbidden protocols", | |
| 69 | + OFFSET(protocol_whitelist), AV_OPT_TYPE_STRING }, | |
| 70 | + { NULL }, | |
| 71 | +}; | |
| 72 | + | |
| 73 | +static const AVClass io_priv_class = { | |
| 74 | + .class_name = "AVIOContext", | |
| 75 | + .item_name = av_default_item_name, | |
| 76 | + .version = LIBAVUTIL_VERSION_INT, | |
| 77 | + .option = io_priv_options, | |
| 78 | + .child_next = io_priv_child_next, | |
| 79 | + .child_class_next = io_priv_child_class_next, | |
| 80 | +}; | |
| 81 | + | |
| 48 | 82 | static void *ff_avio_child_next(void *obj, void *prev) |
| 49 | 83 | { |
| 50 | 84 | AVIOContext *s = obj; |
| 51 | − AVIOInternal *internal = s->opaque; | |
| 52 | − return prev ? NULL : internal->h; | |
| 85 | + return prev ? NULL : s->opaque; | |
| 53 | 86 | } |
| 54 | 87 | |
| 55 | 88 | static const AVClass *ff_avio_child_class_next(const AVClass *prev) |
| 56 | 89 | { |
| 57 | − return prev ? NULL : &ffurl_context_class; | |
| 90 | + return prev ? NULL : &io_priv_class; | |
| 58 | 91 | } |
| 59 | 92 | |
| 60 | 93 | static const AVOption ff_avio_options[] = { |
| @@ -750,8 +783,11 @@ int ffio_fdopen(AVIOContext **s, URLContext *h) · 689 unmodified lines | ||
| 750 | 783 | if (!internal) |
| 751 | 784 | goto fail; |
| 752 | 785 | |
| 786 | + internal->class = &io_priv_class; | |
| 753 | 787 | internal->h = h; |
| 754 | 788 | |
| 789 | + av_opt_set_defaults(internal); | |
| 790 | + | |
| 755 | 791 | *s = avio_alloc_context(buffer, buffer_size, h->flags & AVIO_FLAG_WRITE, |
| 756 | 792 | internal, io_read_packet, io_write_packet, io_seek); |
| 757 | 793 | if (!*s) |
| @@ -766,6 +802,8 @@ int ffio_fdopen(AVIOContext **s, URLContext *h) · 8 unmodified lines | ||
| 766 | 802 | (*s)->av_class = &ff_avio_class; |
| 767 | 803 | return 0; |
| 768 | 804 | fail: |
| 805 | + if (internal) | |
| 806 | + av_opt_free(internal); | |
| 769 | 807 | av_freep(&internal); |
| 770 | 808 | av_freep(&buffer); |
| 771 | 809 | return AVERROR(ENOMEM); |
| @@ -849,10 +887,21 @@ int avio_open2(AVIOContext **s, const char *filename, int flags, · 77 unmodified lines | ||
| 849 | 887 | { |
| 850 | 888 | AVIOInternal *internal; |
| 851 | 889 | const URLProtocol **protocols; |
| 890 | + char *proto_whitelist = NULL, *proto_blacklist = NULL; | |
| 891 | + AVDictionaryEntry *e; | |
| 852 | 892 | URLContext *h; |
| 853 | 893 | int err; |
| 854 | 894 | |
| 855 | − protocols = ffurl_get_protocols(NULL, NULL); | |
| 895 | + if (options) { | |
| 896 | + e = av_dict_get(*options, "protocol_whitelist", NULL, 0); | |
| 897 | + if (e) | |
| 898 | + proto_whitelist = e->value; | |
| 899 | + e = av_dict_get(*options, "protocol_blacklist", NULL, 0); | |
| 900 | + if (e) | |
| 901 | + proto_blacklist = e->value; | |
| 902 | + } | |
| 903 | + | |
| 904 | + protocols = ffurl_get_protocols(proto_whitelist, proto_blacklist); | |
| 856 | 905 | if (!protocols) |
| 857 | 906 | return AVERROR(ENOMEM); |
| 858 | 907 | |
| @@ -872,6 +921,14 @@ int avio_open2(AVIOContext **s, const char *filename, int flags, · 13 unmodified lines | ||
| 872 | 921 | internal = (*s)->opaque; |
| 873 | 922 | internal->protocols = protocols; |
| 874 | 923 | |
| 924 | + if (options) { | |
| 925 | + err = av_opt_set_dict(internal, options); | |
| 926 | + if (err < 0) { | |
| 927 | + avio_closep(s); | |
| 928 | + return err; | |
| 929 | + } | |
| 930 | + } | |
| 931 | + | |
| 875 | 932 | return 0; |
| 876 | 933 | } |
| 877 | 934 | |
| @@ -887,6 +944,8 @@ int avio_close(AVIOContext *s) · 9 unmodified lines | ||
| 887 | 944 | internal = s->opaque; |
| 888 | 945 | h = internal->h; |
| 889 | 946 | |
| 947 | + av_opt_free(internal); | |
| 948 | + | |
| 890 | 949 | av_freep(&internal->protocols); |
| 891 | 950 | av_freep(&s->opaque); |
| 892 | 951 | av_freep(&s->buffer); |
| @@ -20,6 +20,7 @@ · 19 unmodified lines | ||
| 20 | 20 | #include "avformat.h" |
| 21 | 21 | #include "avio_internal.h" |
| 22 | 22 | #include "internal.h" |
| 23 | +#include "url.h" | |
| 23 | 24 | |
| 24 | 25 | #include "libavutil/internal.h" |
| 25 | 26 | #include "libavutil/opt.h" |
| @@ -93,7 +94,26 @@ static const AVClass av_format_context_class = { · 67 unmodified lines | ||
| 93 | 94 | static int io_open_default(AVFormatContext *s, AVIOContext **pb, |
| 94 | 95 | const char *url, int flags, AVDictionary **options) |
| 95 | 96 | { |
| 96 | − return avio_open2(pb, url, flags, &s->interrupt_callback, options); | |
| 97 | + AVDictionary *opts_local = NULL; | |
| 98 | + int ret; | |
| 99 | + | |
| 100 | + if (!options) | |
| 101 | + options = &opts_local; | |
| 102 | + | |
| 103 | + if (s->protocol_whitelist) { | |
| 104 | + ret = av_dict_set(options, "protocol_whitelist", s->protocol_whitelist, 0); | |
| 105 | + if (ret < 0) | |
| 106 | + goto finish; | |
| 107 | + } | |
| 108 | + if (s->protocol_blacklist) { | |
| 109 | + ret = av_dict_set(options, "protocol_blacklist", s->protocol_blacklist, 0); | |
| 110 | + if (ret < 0) | |
| 111 | + goto finish; | |
| 112 | + } | |
| 113 | + ret = avio_open2(pb, url, flags, &s->interrupt_callback, options); | |
| 114 | +finish: | |
| 115 | + av_dict_free(&opts_local); | |
| 116 | + return ret; | |
| 97 | 117 | } |
| 98 | 118 | |
| 99 | 119 | static void io_close_default(AVFormatContext *s, AVIOContext *pb) |
| @@ -70,6 +70,10 @@ static const AVOption avformat_options[] = { · 69 unmodified lines | ||
| 70 | 70 | {"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"}, |
| 71 | 71 | {"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"}, |
| 72 | 72 | {"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"}, |
| 73 | +{"protocol_blacklist", "A comma-separated list of blacklisted protocols used for opening files internally by lavf", | |
| 74 | + OFFSET(protocol_blacklist), AV_OPT_TYPE_STRING, { .str = "concat" }, .flags = E | D }, | |
| 75 | +{"protocol_whitelist", "A comma-separated list of whitelisted protocols used for opening files internally by lavf", | |
| 76 | + OFFSET(protocol_whitelist), AV_OPT_TYPE_STRING, { .str = NULL }, .flags = E | D }, | |
| 73 | 77 | {NULL}, |
| 74 | 78 | }; |
| 75 | 79 | |
| @@ -1668,7 +1668,8 @@ int ff_rtsp_connect(AVFormatContext *s) · 1667 unmodified lines | ||
| 1668 | 1668 | return AVERROR(EIO); |
| 1669 | 1669 | |
| 1670 | 1670 | if (!rt->protocols) { |
| 1671 | − rt->protocols = ffurl_get_protocols(NULL, NULL); | |
| 1671 | + rt->protocols = ffurl_get_protocols(s->protocol_whitelist, | |
| 1672 | + s->protocol_blacklist); | |
| 1672 | 1673 | if (!rt->protocols) |
| 1673 | 1674 | return AVERROR(ENOMEM); |
| 1674 | 1675 | } |
| @@ -2252,7 +2253,8 @@ static int sdp_read_header(AVFormatContext *s) · 577 unmodified lines | ||
| 2252 | 2253 | return AVERROR(EIO); |
| 2253 | 2254 | |
| 2254 | 2255 | if (!rt->protocols) { |
| 2255 | − rt->protocols = ffurl_get_protocols(NULL, NULL); | |
| 2256 | + rt->protocols = ffurl_get_protocols(s->protocol_whitelist, | |
| 2257 | + s->protocol_blacklist); | |
| 2256 | 2258 | if (!rt->protocols) |
| 2257 | 2259 | return AVERROR(ENOMEM); |
| 2258 | 2260 | } |
| @@ -2379,7 +2381,8 @@ static int rtp_read_header(AVFormatContext *s) · 120 unmodified lines | ||
| 2379 | 2381 | return AVERROR(EIO); |
| 2380 | 2382 | |
| 2381 | 2383 | if (!rt->protocols) { |
| 2382 | − rt->protocols = ffurl_get_protocols(NULL, NULL); | |
| 2384 | + rt->protocols = ffurl_get_protocols(s->protocol_whitelist, | |
| 2385 | + s->protocol_blacklist); | |
| 2383 | 2386 | if (!rt->protocols) |
| 2384 | 2387 | return AVERROR(ENOMEM); |
| 2385 | 2388 | } |
| @@ -640,7 +640,8 @@ static int rtsp_listen(AVFormatContext *s) · 639 unmodified lines | ||
| 640 | 640 | enum RTSPMethod methodcode; |
| 641 | 641 | |
| 642 | 642 | if (!rt->protocols) { |
| 643 | − rt->protocols = ffurl_get_protocols(NULL, NULL); | |
| 643 | + rt->protocols = ffurl_get_protocols(s->protocol_whitelist, | |
| 644 | + s->protocol_blacklist); | |
| 644 | 645 | if (!rt->protocols) |
| 645 | 646 | return AVERROR(ENOMEM); |
| 646 | 647 | } |
| @@ -85,7 +85,8 @@ static int sap_read_header(AVFormatContext *s) · 84 unmodified lines | ||
| 85 | 85 | av_strlcpy(host, "224.2.127.254", sizeof(host)); |
| 86 | 86 | } |
| 87 | 87 | |
| 88 | − sap->protocols = ffurl_get_protocols(NULL, NULL); | |
| 88 | + sap->protocols = ffurl_get_protocols(s->protocol_whitelist, | |
| 89 | + s->protocol_blacklist); | |
| 89 | 90 | if (!sap->protocols) { |
| 90 | 91 | ret = AVERROR(ENOMEM); |
| 91 | 92 | goto fail; |
| @@ -138,7 +138,8 @@ static int sap_write_header(AVFormatContext *s) · 137 unmodified lines | ||
| 138 | 138 | freeaddrinfo(ai); |
| 139 | 139 | } |
| 140 | 140 | |
| 141 | − sap->protocols = ffurl_get_protocols(NULL, NULL); | |
| 141 | + sap->protocols = ffurl_get_protocols(s->protocol_whitelist, | |
| 142 | + s->protocol_blacklist); | |
| 142 | 143 | if (!sap->protocols) { |
| 143 | 144 | ret = AVERROR(ENOMEM); |
| 144 | 145 | goto fail; |
| @@ -312,7 +312,7 @@ static int ism_write_header(AVFormatContext *s) · 311 unmodified lines | ||
| 312 | 312 | goto fail; |
| 313 | 313 | } |
| 314 | 314 | |
| 315 | − c->protocols = ffurl_get_protocols(NULL, NULL); | |
| 315 | + c->protocols = ffurl_get_protocols(s->protocol_whitelist, s->protocol_blacklist); | |
| 316 | 316 | if (!c->protocols) { |
| 317 | 317 | ret = AVERROR(ENOMEM); |
| 318 | 318 | goto fail; |
| @@ -30,7 +30,7 @@ · 29 unmodified lines | ||
| 30 | 30 | #include "libavutil/version.h" |
| 31 | 31 | |
| 32 | 32 | #define LIBAVFORMAT_VERSION_MAJOR 57 |
| 33 | −#define LIBAVFORMAT_VERSION_MINOR 3 | |
| 33 | +#define LIBAVFORMAT_VERSION_MINOR 4 | |
| 34 | 34 | #define LIBAVFORMAT_VERSION_MICRO 0 |
| 35 | 35 | |
| 36 | 36 | #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \ |