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 | API changes, most recent first: | 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 | 2016-xx-xx - lavc 57.13.0 - avcodec.h | 21 | 2016-xx-xx - lavc 57.13.0 - avcodec.h |
| 17 | Add AVCodecContext.hw_frames_ctx. | 22 | Add AVCodecContext.hw_frames_ctx. |
| 18 | 23 | ||
| @@ -1261,6 +1261,24 @@ typedef struct AVFormatContext { · 1260 unmodified lines | |||
| 1261 | * A callback for closing the streams opened with AVFormatContext.io_open(). | 1261 | * A callback for closing the streams opened with AVFormatContext.io_open(). |
| 1262 | */ | 1262 | */ |
| 1263 | void (*io_close)(struct AVFormatContext *s, AVIOContext *pb); | 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 | } AVFormatContext; | 1282 | } AVFormatContext; |
| 1265 | 1283 | ||
| 1266 | typedef struct AVPacketList { | 1284 | typedef struct AVPacketList { |
| @@ -41,20 +41,53 @@ · 40 unmodified lines | |||
| 41 | #define SHORT_SEEK_THRESHOLD 4096 | 41 | #define SHORT_SEEK_THRESHOLD 4096 |
| 42 | 42 | ||
| 43 | typedef struct AVIOInternal { | 43 | typedef struct AVIOInternal { |
| 44 | const AVClass *class; | ||
| 45 | |||
| 46 | char *protocol_whitelist; | ||
| 47 | char *protocol_blacklist; | ||
| 48 | |||
| 44 | URLContext *h; | 49 | URLContext *h; |
| 45 | const URLProtocol **protocols; | 50 | const URLProtocol **protocols; |
| 46 | } AVIOInternal; | 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 | static void *ff_avio_child_next(void *obj, void *prev) | 82 | static void *ff_avio_child_next(void *obj, void *prev) |
| 49 | { | 83 | { |
| 50 | AVIOContext *s = obj; | 84 | AVIOContext *s = obj; |
| 51 | AVIOInternal *internal = s->opaque; | 85 | return prev ? NULL : s->opaque; |
| 52 | return prev ? NULL : internal->h; | ||
| 53 | } | 86 | } |
| 54 | 87 | ||
| 55 | static const AVClass *ff_avio_child_class_next(const AVClass *prev) | 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 | static const AVOption ff_avio_options[] = { | 93 | static const AVOption ff_avio_options[] = { |
| @@ -750,8 +783,11 @@ int ffio_fdopen(AVIOContext **s, URLContext *h) · 689 unmodified lines | |||
| 750 | if (!internal) | 783 | if (!internal) |
| 751 | goto fail; | 784 | goto fail; |
| 752 | 785 | ||
| 786 | internal->class = &io_priv_class; | ||
| 753 | internal->h = h; | 787 | internal->h = h; |
| 754 | 788 | ||
| 789 | av_opt_set_defaults(internal); | ||
| 790 | |||
| 755 | *s = avio_alloc_context(buffer, buffer_size, h->flags & AVIO_FLAG_WRITE, | 791 | *s = avio_alloc_context(buffer, buffer_size, h->flags & AVIO_FLAG_WRITE, |
| 756 | internal, io_read_packet, io_write_packet, io_seek); | 792 | internal, io_read_packet, io_write_packet, io_seek); |
| 757 | if (!*s) | 793 | if (!*s) |
| @@ -766,6 +802,8 @@ int ffio_fdopen(AVIOContext **s, URLContext *h) · 8 unmodified lines | |||
| 766 | (*s)->av_class = &ff_avio_class; | 802 | (*s)->av_class = &ff_avio_class; |
| 767 | return 0; | 803 | return 0; |
| 768 | fail: | 804 | fail: |
| 805 | if (internal) | ||
| 806 | av_opt_free(internal); | ||
| 769 | av_freep(&internal); | 807 | av_freep(&internal); |
| 770 | av_freep(&buffer); | 808 | av_freep(&buffer); |
| 771 | return AVERROR(ENOMEM); | 809 | return AVERROR(ENOMEM); |
| @@ -849,10 +887,21 @@ int avio_open2(AVIOContext **s, const char *filename, int flags, · 77 unmodified lines | |||
| 849 | { | 887 | { |
| 850 | AVIOInternal *internal; | 888 | AVIOInternal *internal; |
| 851 | const URLProtocol **protocols; | 889 | const URLProtocol **protocols; |
| 890 | char *proto_whitelist = NULL, *proto_blacklist = NULL; | ||
| 891 | AVDictionaryEntry *e; | ||
| 852 | URLContext *h; | 892 | URLContext *h; |
| 853 | int err; | 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 | if (!protocols) | 905 | if (!protocols) |
| 857 | return AVERROR(ENOMEM); | 906 | return AVERROR(ENOMEM); |
| 858 | 907 | ||
| @@ -872,6 +921,14 @@ int avio_open2(AVIOContext **s, const char *filename, int flags, · 13 unmodified lines | |||
| 872 | internal = (*s)->opaque; | 921 | internal = (*s)->opaque; |
| 873 | internal->protocols = protocols; | 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 | return 0; | 932 | return 0; |
| 876 | } | 933 | } |
| 877 | 934 | ||
| @@ -887,6 +944,8 @@ int avio_close(AVIOContext *s) · 9 unmodified lines | |||
| 887 | internal = s->opaque; | 944 | internal = s->opaque; |
| 888 | h = internal->h; | 945 | h = internal->h; |
| 889 | 946 | ||
| 947 | av_opt_free(internal); | ||
| 948 | |||
| 890 | av_freep(&internal->protocols); | 949 | av_freep(&internal->protocols); |
| 891 | av_freep(&s->opaque); | 950 | av_freep(&s->opaque); |
| 892 | av_freep(&s->buffer); | 951 | av_freep(&s->buffer); |
| @@ -20,6 +20,7 @@ · 19 unmodified lines | |||
| 20 | #include "avformat.h" | 20 | #include "avformat.h" |
| 21 | #include "avio_internal.h" | 21 | #include "avio_internal.h" |
| 22 | #include "internal.h" | 22 | #include "internal.h" |
| 23 | #include "url.h" | ||
| 23 | 24 | ||
| 24 | #include "libavutil/internal.h" | 25 | #include "libavutil/internal.h" |
| 25 | #include "libavutil/opt.h" | 26 | #include "libavutil/opt.h" |
| @@ -93,7 +94,26 @@ static const AVClass av_format_context_class = { · 67 unmodified lines | |||
| 93 | static int io_open_default(AVFormatContext *s, AVIOContext **pb, | 94 | static int io_open_default(AVFormatContext *s, AVIOContext **pb, |
| 94 | const char *url, int flags, AVDictionary **options) | 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 | static void io_close_default(AVFormatContext *s, AVIOContext *pb) | 119 | static void io_close_default(AVFormatContext *s, AVIOContext *pb) |
| @@ -70,6 +70,10 @@ static const AVOption avformat_options[] = { · 69 unmodified lines | |||
| 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"}, | 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 | {"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"}, | 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 | {"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"}, | 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 | {NULL}, | 77 | {NULL}, |
| 74 | }; | 78 | }; |
| 75 | 79 | ||
| @@ -1668,7 +1668,8 @@ int ff_rtsp_connect(AVFormatContext *s) · 1667 unmodified lines | |||
| 1668 | return AVERROR(EIO); | 1668 | return AVERROR(EIO); |
| 1669 | 1669 | ||
| 1670 | if (!rt->protocols) { | 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 | if (!rt->protocols) | 1673 | if (!rt->protocols) |
| 1673 | return AVERROR(ENOMEM); | 1674 | return AVERROR(ENOMEM); |
| 1674 | } | 1675 | } |
| @@ -2252,7 +2253,8 @@ static int sdp_read_header(AVFormatContext *s) · 577 unmodified lines | |||
| 2252 | return AVERROR(EIO); | 2253 | return AVERROR(EIO); |
| 2253 | 2254 | ||
| 2254 | if (!rt->protocols) { | 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 | if (!rt->protocols) | 2258 | if (!rt->protocols) |
| 2257 | return AVERROR(ENOMEM); | 2259 | return AVERROR(ENOMEM); |
| 2258 | } | 2260 | } |
| @@ -2379,7 +2381,8 @@ static int rtp_read_header(AVFormatContext *s) · 120 unmodified lines | |||
| 2379 | return AVERROR(EIO); | 2381 | return AVERROR(EIO); |
| 2380 | 2382 | ||
| 2381 | if (!rt->protocols) { | 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 | if (!rt->protocols) | 2386 | if (!rt->protocols) |
| 2384 | return AVERROR(ENOMEM); | 2387 | return AVERROR(ENOMEM); |
| 2385 | } | 2388 | } |
| @@ -640,7 +640,8 @@ static int rtsp_listen(AVFormatContext *s) · 639 unmodified lines | |||
| 640 | enum RTSPMethod methodcode; | 640 | enum RTSPMethod methodcode; |
| 641 | 641 | ||
| 642 | if (!rt->protocols) { | 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 | if (!rt->protocols) | 645 | if (!rt->protocols) |
| 645 | return AVERROR(ENOMEM); | 646 | return AVERROR(ENOMEM); |
| 646 | } | 647 | } |
| @@ -85,7 +85,8 @@ static int sap_read_header(AVFormatContext *s) · 84 unmodified lines | |||
| 85 | av_strlcpy(host, "224.2.127.254", sizeof(host)); | 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 | if (!sap->protocols) { | 90 | if (!sap->protocols) { |
| 90 | ret = AVERROR(ENOMEM); | 91 | ret = AVERROR(ENOMEM); |
| 91 | goto fail; | 92 | goto fail; |
| @@ -138,7 +138,8 @@ static int sap_write_header(AVFormatContext *s) · 137 unmodified lines | |||
| 138 | freeaddrinfo(ai); | 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 | if (!sap->protocols) { | 143 | if (!sap->protocols) { |
| 143 | ret = AVERROR(ENOMEM); | 144 | ret = AVERROR(ENOMEM); |
| 144 | goto fail; | 145 | goto fail; |
| @@ -312,7 +312,7 @@ static int ism_write_header(AVFormatContext *s) · 311 unmodified lines | |||
| 312 | goto fail; | 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 | if (!c->protocols) { | 316 | if (!c->protocols) { |
| 317 | ret = AVERROR(ENOMEM); | 317 | ret = AVERROR(ENOMEM); |
| 318 | goto fail; | 318 | goto fail; |
| @@ -30,7 +30,7 @@ · 29 unmodified lines | |||
| 30 | #include "libavutil/version.h" | 30 | #include "libavutil/version.h" |
| 31 | 31 | ||
| 32 | #define LIBAVFORMAT_VERSION_MAJOR 57 | 32 | #define LIBAVFORMAT_VERSION_MAJOR 57 |
| 33 | #define LIBAVFORMAT_VERSION_MINOR 3 | 33 | #define LIBAVFORMAT_VERSION_MINOR 4 |
| 34 | #define LIBAVFORMAT_VERSION_MICRO 0 | 34 | #define LIBAVFORMAT_VERSION_MICRO 0 |
| 35 | 35 | ||
| 36 | #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \ | 36 | #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \ |