History

lavf: add a protocol whitelist/blacklist for file opened internally

Should make the default behaviour safer for careless callers that open random untrusted files.

Anton Khirnov committed 10 years ago

Commit ec4c4831 parent 8c0ceaf11 files · +125 −13Browse files

Unified · Split

11 files
  1. doc/APIchanges +5 −0
  2. libavformat/avformat.h +18 −0
  3. libavformat/aviobuf.c +63 −4
  4. libavformat/options.c +21 −1
  5. libavformat/options_table.h +4 −0
  6. libavformat/rtsp.c +6 −3
  7. libavformat/rtspdec.c +2 −1
  8. libavformat/sapdec.c +2 −1
  9. libavformat/sapenc.c +2 −1
  10. libavformat/smoothstreamingenc.c +1 −1
  11. libavformat/version.h +1 −1
doc/APIchanges+5−0
@@ -13,6 +13,11 @@ libavutil: 2015-08-28 · 12 unmodified lines
13 13
14API changes, most recent first:14API changes, most recent first:
15 15
162016-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
162016-xx-xx - lavc 57.13.0 - avcodec.h212016-xx-xx - lavc 57.13.0 - avcodec.h
17 Add AVCodecContext.hw_frames_ctx.22 Add AVCodecContext.hw_frames_ctx.
18 23
libavformat/avformat.h+18−0
@@ -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
1266typedef struct AVPacketList {1284typedef struct AVPacketList {
libavformat/aviobuf.c+63−4
@@ -41,20 +41,53 @@ · 40 unmodified lines
41#define SHORT_SEEK_THRESHOLD 409641#define SHORT_SEEK_THRESHOLD 4096
42 42
43typedef struct AVIOInternal {43typedef 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
53static void *io_priv_child_next(void *obj, void *prev)
54{
55 AVIOInternal *internal = obj;
56 return prev ? NULL : internal->h;
57}
58
59static 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)
65static 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
73static 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
48static void *ff_avio_child_next(void *obj, void *prev)82static 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
55static const AVClass *ff_avio_child_class_next(const AVClass *prev)88static 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
60static const AVOption ff_avio_options[] = {93static 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;
768fail:804fail:
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);
libavformat/options.c+21−1
@@ -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
93static int io_open_default(AVFormatContext *s, AVIOContext **pb,94static 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);
114finish:
115 av_dict_free(&opts_local);
116 return ret;
97}117}
98 118
99static void io_close_default(AVFormatContext *s, AVIOContext *pb)119static void io_close_default(AVFormatContext *s, AVIOContext *pb)
libavformat/options_table.h+4−0
@@ -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
libavformat/rtsp.c+6−3
@@ -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 }
libavformat/rtspdec.c+2−1
@@ -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 }
libavformat/sapdec.c+2−1
@@ -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;
libavformat/sapenc.c+2−1
@@ -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;
libavformat/smoothstreamingenc.c+1−1
@@ -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;
libavformat/version.h+1−1
@@ -30,7 +30,7 @@ · 29 unmodified lines
30#include "libavutil/version.h"30#include "libavutil/version.h"
31 31
32#define LIBAVFORMAT_VERSION_MAJOR 5732#define LIBAVFORMAT_VERSION_MAJOR 57
33#define LIBAVFORMAT_VERSION_MINOR 333#define LIBAVFORMAT_VERSION_MINOR 4
34#define LIBAVFORMAT_VERSION_MICRO 034#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, \

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t