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
1313
1414 API changes, most recent first:
1515
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+
1621 2016-xx-xx - lavc 57.13.0 - avcodec.h
1722 Add AVCodecContext.hw_frames_ctx.
1823
libavformat/avformat.h+18−0
@@ -1261,6 +1261,24 @@ typedef struct AVFormatContext { · 1260 unmodified lines
12611261 * A callback for closing the streams opened with AVFormatContext.io_open().
12621262 */
12631263 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;
12641282 } AVFormatContext;
12651283
12661284 typedef struct AVPacketList {
libavformat/aviobuf.c+63−4
@@ -41,20 +41,53 @@ · 40 unmodified lines
4141 #define SHORT_SEEK_THRESHOLD 4096
4242
4343 typedef struct AVIOInternal {
44+ const AVClass *class;
45+
46+ char *protocol_whitelist;
47+ char *protocol_blacklist;
48+
4449 URLContext *h;
4550 const URLProtocol **protocols;
4651 } AVIOInternal;
4752
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+
4882 static void *ff_avio_child_next(void *obj, void *prev)
4983 {
5084 AVIOContext *s = obj;
51− AVIOInternal *internal = s->opaque;
52− return prev ? NULL : internal->h;
85+ return prev ? NULL : s->opaque;
5386 }
5487
5588 static const AVClass *ff_avio_child_class_next(const AVClass *prev)
5689 {
57− return prev ? NULL : &ffurl_context_class;
90+ return prev ? NULL : &io_priv_class;
5891 }
5992
6093 static const AVOption ff_avio_options[] = {
@@ -750,8 +783,11 @@ int ffio_fdopen(AVIOContext **s, URLContext *h) · 689 unmodified lines
750783 if (!internal)
751784 goto fail;
752785
786+ internal->class = &io_priv_class;
753787 internal->h = h;
754788
789+ av_opt_set_defaults(internal);
790+
755791 *s = avio_alloc_context(buffer, buffer_size, h->flags & AVIO_FLAG_WRITE,
756792 internal, io_read_packet, io_write_packet, io_seek);
757793 if (!*s)
@@ -766,6 +802,8 @@ int ffio_fdopen(AVIOContext **s, URLContext *h) · 8 unmodified lines
766802 (*s)->av_class = &ff_avio_class;
767803 return 0;
768804 fail:
805+ if (internal)
806+ av_opt_free(internal);
769807 av_freep(&internal);
770808 av_freep(&buffer);
771809 return AVERROR(ENOMEM);
@@ -849,10 +887,21 @@ int avio_open2(AVIOContext **s, const char *filename, int flags, · 77 unmodified lines
849887 {
850888 AVIOInternal *internal;
851889 const URLProtocol **protocols;
890+ char *proto_whitelist = NULL, *proto_blacklist = NULL;
891+ AVDictionaryEntry *e;
852892 URLContext *h;
853893 int err;
854894
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);
856905 if (!protocols)
857906 return AVERROR(ENOMEM);
858907
@@ -872,6 +921,14 @@ int avio_open2(AVIOContext **s, const char *filename, int flags, · 13 unmodified lines
872921 internal = (*s)->opaque;
873922 internal->protocols = protocols;
874923
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+
875932 return 0;
876933 }
877934
@@ -887,6 +944,8 @@ int avio_close(AVIOContext *s) · 9 unmodified lines
887944 internal = s->opaque;
888945 h = internal->h;
889946
947+ av_opt_free(internal);
948+
890949 av_freep(&internal->protocols);
891950 av_freep(&s->opaque);
892951 av_freep(&s->buffer);
libavformat/options.c+21−1
@@ -20,6 +20,7 @@ · 19 unmodified lines
2020 #include "avformat.h"
2121 #include "avio_internal.h"
2222 #include "internal.h"
23+#include "url.h"
2324
2425 #include "libavutil/internal.h"
2526 #include "libavutil/opt.h"
@@ -93,7 +94,26 @@ static const AVClass av_format_context_class = { · 67 unmodified lines
9394 static int io_open_default(AVFormatContext *s, AVIOContext **pb,
9495 const char *url, int flags, AVDictionary **options)
9596 {
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;
97117 }
98118
99119 static 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
7070 {"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"},
7171 {"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"},
7272 {"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 },
7377 {NULL},
7478 };
7579
libavformat/rtsp.c+6−3
@@ -1668,7 +1668,8 @@ int ff_rtsp_connect(AVFormatContext *s) · 1667 unmodified lines
16681668 return AVERROR(EIO);
16691669
16701670 if (!rt->protocols) {
1671− rt->protocols = ffurl_get_protocols(NULL, NULL);
1671+ rt->protocols = ffurl_get_protocols(s->protocol_whitelist,
1672+ s->protocol_blacklist);
16721673 if (!rt->protocols)
16731674 return AVERROR(ENOMEM);
16741675 }
@@ -2252,7 +2253,8 @@ static int sdp_read_header(AVFormatContext *s) · 577 unmodified lines
22522253 return AVERROR(EIO);
22532254
22542255 if (!rt->protocols) {
2255− rt->protocols = ffurl_get_protocols(NULL, NULL);
2256+ rt->protocols = ffurl_get_protocols(s->protocol_whitelist,
2257+ s->protocol_blacklist);
22562258 if (!rt->protocols)
22572259 return AVERROR(ENOMEM);
22582260 }
@@ -2379,7 +2381,8 @@ static int rtp_read_header(AVFormatContext *s) · 120 unmodified lines
23792381 return AVERROR(EIO);
23802382
23812383 if (!rt->protocols) {
2382− rt->protocols = ffurl_get_protocols(NULL, NULL);
2384+ rt->protocols = ffurl_get_protocols(s->protocol_whitelist,
2385+ s->protocol_blacklist);
23832386 if (!rt->protocols)
23842387 return AVERROR(ENOMEM);
23852388 }
libavformat/rtspdec.c+2−1
@@ -640,7 +640,8 @@ static int rtsp_listen(AVFormatContext *s) · 639 unmodified lines
640640 enum RTSPMethod methodcode;
641641
642642 if (!rt->protocols) {
643− rt->protocols = ffurl_get_protocols(NULL, NULL);
643+ rt->protocols = ffurl_get_protocols(s->protocol_whitelist,
644+ s->protocol_blacklist);
644645 if (!rt->protocols)
645646 return AVERROR(ENOMEM);
646647 }
libavformat/sapdec.c+2−1
@@ -85,7 +85,8 @@ static int sap_read_header(AVFormatContext *s) · 84 unmodified lines
8585 av_strlcpy(host, "224.2.127.254", sizeof(host));
8686 }
8787
88− sap->protocols = ffurl_get_protocols(NULL, NULL);
88+ sap->protocols = ffurl_get_protocols(s->protocol_whitelist,
89+ s->protocol_blacklist);
8990 if (!sap->protocols) {
9091 ret = AVERROR(ENOMEM);
9192 goto fail;
libavformat/sapenc.c+2−1
@@ -138,7 +138,8 @@ static int sap_write_header(AVFormatContext *s) · 137 unmodified lines
138138 freeaddrinfo(ai);
139139 }
140140
141− sap->protocols = ffurl_get_protocols(NULL, NULL);
141+ sap->protocols = ffurl_get_protocols(s->protocol_whitelist,
142+ s->protocol_blacklist);
142143 if (!sap->protocols) {
143144 ret = AVERROR(ENOMEM);
144145 goto fail;
libavformat/smoothstreamingenc.c+1−1
@@ -312,7 +312,7 @@ static int ism_write_header(AVFormatContext *s) · 311 unmodified lines
312312 goto fail;
313313 }
314314
315− c->protocols = ffurl_get_protocols(NULL, NULL);
315+ c->protocols = ffurl_get_protocols(s->protocol_whitelist, s->protocol_blacklist);
316316 if (!c->protocols) {
317317 ret = AVERROR(ENOMEM);
318318 goto fail;
libavformat/version.h+1−1
@@ -30,7 +30,7 @@ · 29 unmodified lines
3030 #include "libavutil/version.h"
3131
3232 #define LIBAVFORMAT_VERSION_MAJOR 57
33−#define LIBAVFORMAT_VERSION_MINOR 3
33+#define LIBAVFORMAT_VERSION_MINOR 4
3434 #define LIBAVFORMAT_VERSION_MICRO 0
3535
3636 #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