diff options
Diffstat (limited to 'stream')
-rw-r--r-- | stream/stream.c | 61 | ||||
-rw-r--r-- | stream/stream.h | 29 | ||||
-rw-r--r-- | stream/stream_avdevice.c | 1 | ||||
-rw-r--r-- | stream/stream_bluray.c | 3 | ||||
-rw-r--r-- | stream/stream_cb.c | 1 | ||||
-rw-r--r-- | stream/stream_cdda.c | 1 | ||||
-rw-r--r-- | stream/stream_concat.c | 2 | ||||
-rw-r--r-- | stream/stream_dvb.c | 1 | ||||
-rw-r--r-- | stream/stream_dvdnav.c | 4 | ||||
-rw-r--r-- | stream/stream_file.c | 2 | ||||
-rw-r--r-- | stream/stream_lavf.c | 6 | ||||
-rw-r--r-- | stream/stream_libarchive.c | 10 | ||||
-rw-r--r-- | stream/stream_memory.c | 2 | ||||
-rw-r--r-- | stream/stream_smb.c | 1 |
14 files changed, 87 insertions, 37 deletions
diff --git a/stream/stream.c b/stream/stream.c index 271e268a1c..157776cd87 100644 --- a/stream/stream.c +++ b/stream/stream.c @@ -101,6 +101,7 @@ static const stream_info_t *const stream_list[] = { struct stream_opts { int64_t buffer_size; + int load_unsafe_playlists; }; #define OPT_BASE_STRUCT struct stream_opts @@ -109,6 +110,7 @@ const struct m_sub_options stream_conf = { .opts = (const struct m_option[]){ OPT_BYTE_SIZE("stream-buffer-size", buffer_size, 0, STREAM_MIN_BUFFER_SIZE, 512 * 1024 * 1024), + OPT_FLAG("load-unsafe-playlists", load_unsafe_playlists, 0), {0} }, .size = sizeof(struct stream_opts), @@ -202,6 +204,30 @@ static const char *match_proto(const char *url, const char *proto) return NULL; } +// src and new are both STREAM_ORIGIN_* values. This checks whether a stream +// with flags "new" can be opened from the "src". On success, return +// new origin, on incompatibility return 0. +static int check_origin(int src, int new) +{ + switch (src) { + case STREAM_ORIGIN_DIRECT: + case STREAM_ORIGIN_UNSAFE: + // Allow anything, but constrain it to the new origin. + return new; + case STREAM_ORIGIN_FS: + // From unix FS, allow all but unsafe. + if (new == STREAM_ORIGIN_FS || new == STREAM_ORIGIN_NET) + return new; + break; + case STREAM_ORIGIN_NET: + // Allow only other network links. + if (new == STREAM_ORIGIN_NET) + return new; + break; + } + return 0; +} + // Read len bytes from the start position, and wrap around as needed. Limit the // actually read data to the size of the buffer. Return amount of copied bytes. // len: max bytes to copy to dst @@ -289,11 +315,6 @@ static int stream_create_instance(const stream_info_t *sinfo, *ret = NULL; - if (!sinfo->is_safe && (flags & STREAM_SAFE_ONLY)) - return STREAM_UNSAFE; - if (!sinfo->is_network && (flags & STREAM_NETWORK_ONLY)) - return STREAM_UNSAFE; - const char *path = url; for (int n = 0; sinfo->protocols && sinfo->protocols[n]; n++) { path = match_proto(url, sinfo->protocols[n]); @@ -304,11 +325,9 @@ static int stream_create_instance(const stream_info_t *sinfo, if (!path) return STREAM_NO_MATCH; - struct stream_opts *opts = - mp_get_config_group(NULL, args->global, &stream_conf); - stream_t *s = talloc_zero(NULL, stream_t); s->global = args->global; + struct stream_opts *opts = mp_get_config_group(s, s->global, &stream_conf); if (flags & STREAM_SILENT) { s->log = mp_null_log; } else { @@ -318,7 +337,6 @@ static int stream_create_instance(const stream_info_t *sinfo, s->cancel = args->cancel; s->url = talloc_strdup(s, url); s->path = talloc_strdup(s, path); - s->is_network = sinfo->is_network; s->mode = flags & (STREAM_READ | STREAM_WRITE); s->requested_buffer_size = opts->buffer_size; @@ -326,8 +344,6 @@ static int stream_create_instance(const stream_info_t *sinfo, mp_read_option_raw(s->global, "access-references", &m_option_type_flag, &opt); s->access_references = opt; - talloc_free(opts); - MP_VERBOSE(s, "Opening %s\n", url); if (strlen(url) > INT_MAX / 8) { @@ -342,6 +358,18 @@ static int stream_create_instance(const stream_info_t *sinfo, return STREAM_NO_MATCH; } + s->stream_origin = flags & STREAM_ORIGIN_MASK; // pass through by default + if (opts->load_unsafe_playlists) { + s->stream_origin = STREAM_ORIGIN_DIRECT; + } else if (sinfo->stream_origin) { + s->stream_origin = check_origin(s->stream_origin, sinfo->stream_origin); + } + + if (!s->stream_origin) { + talloc_free(s); + return STREAM_UNSAFE; + } + int r = STREAM_UNSUPPORTED; if (sinfo->open2) { r = sinfo->open2(s, args); @@ -429,14 +457,10 @@ struct stream *stream_create(const char *url, int flags, return s; } -struct stream *stream_open(const char *filename, struct mpv_global *global) -{ - return stream_create(filename, STREAM_READ, NULL, global); -} - stream_t *open_output_stream(const char *filename, struct mpv_global *global) { - return stream_create(filename, STREAM_WRITE, NULL, global); + return stream_create(filename, STREAM_ORIGIN_DIRECT | STREAM_WRITE, + NULL, global); } // Read function bypassing the local stream buffer. This will not write into @@ -787,7 +811,8 @@ struct bstr stream_read_file(const char *filename, void *talloc_ctx, { struct bstr res = {0}; char *fname = mp_get_user_path(NULL, global, filename); - stream_t *s = stream_open(fname, global); + stream_t *s = + stream_create(fname, STREAM_ORIGIN_DIRECT | STREAM_READ, NULL, global); if (s) { res = stream_read_complete(s, talloc_ctx, max_size); free_stream(s); diff --git a/stream/stream.h b/stream/stream.h index aa764818b7..c85aeffd73 100644 --- a/stream/stream.h +++ b/stream/stream.h @@ -32,14 +32,23 @@ // it's guaranteed that you can seek back by <= of this size again. #define STREAM_BUFFER_SIZE 2048 +// flags for stream_open_ext (this includes STREAM_READ and STREAM_WRITE) + // stream->mode -#define STREAM_READ 0 -#define STREAM_WRITE 1 +#define STREAM_READ 0 +#define STREAM_WRITE (1 << 0) -// flags for stream_open_ext (this includes STREAM_READ and STREAM_WRITE) -#define STREAM_SAFE_ONLY 4 -#define STREAM_NETWORK_ONLY 8 -#define STREAM_SILENT 16 +#define STREAM_SILENT (1 << 1) + +// Origin value for "security". This is an integer within the flags bit-field. +#define STREAM_ORIGIN_DIRECT (1 << 2) // passed from cmdline or loadfile +#define STREAM_ORIGIN_FS (2 << 2) // referenced from playlist on unix FS +#define STREAM_ORIGIN_NET (3 << 2) // referenced from playlist on network +#define STREAM_ORIGIN_UNSAFE (4 << 2) // from a grotesque source + +#define STREAM_ORIGIN_MASK (7 << 2) // for extracting origin value from flags + +// end flags for stream_open_ext (the naming convention sucks) #define STREAM_UNSAFE -3 #define STREAM_NO_MATCH -2 @@ -100,8 +109,8 @@ typedef struct stream_info_st { int (*open2)(struct stream *st, struct stream_open_args *args); const char *const *protocols; bool can_write; // correctly checks for READ/WRITE modes - bool is_safe; // opening is no security issue, even with remote provided URLs - bool is_network; // used to restrict remote playlist entries to remote URLs + int stream_origin; // 0 or set of STREAM_ORIGIN_*; if 0, the same origin + // is set, or the stream's open() function handles it } stream_info_t; typedef struct stream { @@ -123,6 +132,7 @@ typedef struct stream { int64_t pos; int eof; // valid only after read calls that returned a short result int mode; //STREAM_READ or STREAM_WRITE + int stream_origin; // any STREAM_ORIGIN_* void *priv; // used for DVD, TV, RTSP etc char *url; // filename/url (possibly including protocol prefix) char *path; // filename (url without protocol prefix) @@ -132,7 +142,7 @@ typedef struct stream { bool streaming : 1; // known to be a network stream if true bool seekable : 1; // presence of general byte seeking support bool fast_skip : 1; // consider stream fast enough to fw-seek by skipping - bool is_network : 1; // original stream_info_t.is_network flag + bool is_network : 1; // I really don't know what this is for bool is_local_file : 1; // from the filesystem bool is_directory : 1; // directory on the filesystem bool access_references : 1; // open other streams @@ -223,7 +233,6 @@ struct stream_open_args { int stream_create_with_args(struct stream_open_args *args, struct stream **ret); struct stream *stream_create(const char *url, int flags, struct mp_cancel *c, struct mpv_global *global); -struct stream *stream_open(const char *filename, struct mpv_global *global); stream_t *open_output_stream(const char *filename, struct mpv_global *global); void mp_url_unescape_inplace(char *buf); diff --git a/stream/stream_avdevice.c b/stream/stream_avdevice.c index 5185b7a844..3cfdfe1a53 100644 --- a/stream/stream_avdevice.c +++ b/stream/stream_avdevice.c @@ -30,4 +30,5 @@ const stream_info_t stream_info_avdevice = { .name = "avdevice", .open = open_f, .protocols = (const char*const[]){ "avdevice", "av", NULL }, + .stream_origin = STREAM_ORIGIN_UNSAFE, }; diff --git a/stream/stream_bluray.c b/stream/stream_bluray.c index 1d57730539..19e99a458b 100644 --- a/stream/stream_bluray.c +++ b/stream/stream_bluray.c @@ -512,12 +512,14 @@ const stream_info_t stream_info_bluray = { .name = "bd", .open = bluray_stream_open, .protocols = (const char*const[]){ "bd", "br", "bluray", NULL }, + .stream_origin = STREAM_ORIGIN_UNSAFE, }; const stream_info_t stream_info_bdnav = { .name = "bdnav", .open = bluray_stream_open, .protocols = (const char*const[]){ "bdnav", "brnav", "bluraynav", NULL }, + .stream_origin = STREAM_ORIGIN_UNSAFE, }; static bool check_bdmv(const char *path) @@ -605,4 +607,5 @@ const stream_info_t stream_info_bdmv_dir = { .name = "bdmv/bluray", .open = bdmv_dir_stream_open, .protocols = (const char*const[]){ "file", "", NULL }, + .stream_origin = STREAM_ORIGIN_UNSAFE, }; diff --git a/stream/stream_cb.c b/stream/stream_cb.c index ba0b3e5da3..238dd1ac1c 100644 --- a/stream/stream_cb.c +++ b/stream/stream_cb.c @@ -106,4 +106,5 @@ static int open_cb(stream_t *stream) const stream_info_t stream_info_cb = { .name = "stream_callback", .open = open_cb, + .stream_origin = STREAM_ORIGIN_UNSAFE, }; diff --git a/stream/stream_cdda.c b/stream/stream_cdda.c index 158cfd0646..87be426992 100644 --- a/stream/stream_cdda.c +++ b/stream/stream_cdda.c @@ -401,4 +401,5 @@ const stream_info_t stream_info_cdda = { .name = "cdda", .open = open_cdda, .protocols = (const char*const[]){"cdda", NULL }, + .stream_origin = STREAM_ORIGIN_UNSAFE, }; diff --git a/stream/stream_concat.c b/stream/stream_concat.c index a10fee7912..060583a604 100644 --- a/stream/stream_concat.c +++ b/stream/stream_concat.c @@ -151,7 +151,7 @@ struct stream *stream_concat_open(struct mpv_global *global, struct mp_cancel *c .global = global, .cancel = c, .url = "concat://", - .flags = STREAM_READ | STREAM_SILENT, + .flags = STREAM_READ | STREAM_SILENT | STREAM_ORIGIN_DIRECT, .sinfo = &stream_info_concat, .special_arg = &arg, }; diff --git a/stream/stream_dvb.c b/stream/stream_dvb.c index d6907cb792..c14cce8420 100644 --- a/stream/stream_dvb.c +++ b/stream/stream_dvb.c @@ -1267,4 +1267,5 @@ const stream_info_t stream_info_dvb = { .name = "dvbin", .open = dvb_open, .protocols = (const char *const[]){ "dvb", NULL }, + .stream_origin = STREAM_ORIGIN_UNSAFE, }; diff --git a/stream/stream_dvdnav.c b/stream/stream_dvdnav.c index 619284f393..d858c51aca 100644 --- a/stream/stream_dvdnav.c +++ b/stream/stream_dvdnav.c @@ -575,7 +575,7 @@ static int open_s_internal(stream_t *stream) if (!new_dvdnav_stream(stream, filename)) { MP_ERR(stream, "Couldn't open DVD device: %s\n", filename); - return STREAM_UNSUPPORTED; + return STREAM_ERROR; } if (p->track == TITLE_LONGEST) { // longest @@ -662,6 +662,7 @@ const stream_info_t stream_info_dvdnav = { .name = "dvdnav", .open = open_s, .protocols = (const char*const[]){ "dvd", "dvdnav", NULL }, + .stream_origin = STREAM_ORIGIN_UNSAFE, }; static bool check_ifo(const char *path) @@ -714,4 +715,5 @@ const stream_info_t stream_info_ifo_dvdnav = { .name = "ifo_dvdnav", .open = ifo_dvdnav_stream_open, .protocols = (const char*const[]){ "file", "", NULL }, + .stream_origin = STREAM_ORIGIN_UNSAFE, }; diff --git a/stream/stream_file.c b/stream/stream_file.c index 1ad9a5c7f5..a79ef0e913 100644 --- a/stream/stream_file.c +++ b/stream/stream_file.c @@ -349,5 +349,5 @@ const stream_info_t stream_info_file = { .protocols = (const char*const[]){ "file", "", "fd", "fdclose", "appending", NULL }, .can_write = true, - .is_safe = true, + .stream_origin = STREAM_ORIGIN_FS, }; diff --git a/stream/stream_lavf.c b/stream/stream_lavf.c index 604535c431..c20790a505 100644 --- a/stream/stream_lavf.c +++ b/stream/stream_lavf.c @@ -342,6 +342,8 @@ static int open_f(stream_t *stream) stream->close = close_f; // enable cache (should be avoided for files, but no way to detect this) stream->streaming = true; + if (stream->info->stream_origin == STREAM_ORIGIN_NET) + stream->is_network = true; res = STREAM_OK; out: @@ -418,8 +420,7 @@ const stream_info_t stream_info_ffmpeg = { "gopher", "data", NULL }, .can_write = true, - .is_safe = true, - .is_network = true, + .stream_origin = STREAM_ORIGIN_NET, }; // Unlike above, this is not marked as safe, and can contain protocols which @@ -433,6 +434,7 @@ const stream_info_t stream_info_ffmpeg_unsafe = { "lavf", "ffmpeg", "udp", "ftp", "tcp", "tls", "unix", "sftp", "md5", "concat", NULL }, + .stream_origin = STREAM_ORIGIN_UNSAFE, .can_write = true, }; diff --git a/stream/stream_libarchive.c b/stream/stream_libarchive.c index 2e300f3747..76b47e1633 100644 --- a/stream/stream_libarchive.c +++ b/stream/stream_libarchive.c @@ -93,7 +93,9 @@ static int open_cb(struct archive *arch, void *priv) struct mp_archive_volume *vol = priv; vol->seek_to = -1; if (!vol->src) { - vol->src = stream_create(vol->url, STREAM_READ, + vol->src = stream_create(vol->url, + STREAM_READ | + vol->mpa->primary_src->stream_origin, vol->mpa->primary_src->cancel, vol->mpa->primary_src->global); return vol->src ? ARCHIVE_OK : ARCHIVE_FATAL; @@ -207,7 +209,9 @@ static char **find_volumes(struct stream *primary_stream) struct bstr base = bstr_splice(primary_url, 0, -strlen(pattern->match)); for (int i = pattern->start; i <= pattern->stop; i++) { char* url = pattern->volume_url(res, pattern->format, base, i); - struct stream *s = stream_create(url, STREAM_READ | STREAM_SAFE_ONLY, + struct stream *s = stream_create(url, + STREAM_READ | + primary_stream->stream_origin, primary_stream->cancel, primary_stream->global); if (!s) { @@ -490,7 +494,7 @@ static int archive_entry_open(stream_t *stream) p->entry_name = name + 1; mp_url_unescape_inplace(base); - p->src = stream_create(base, STREAM_READ | STREAM_SAFE_ONLY, + p->src = stream_create(base, STREAM_READ | stream->stream_origin, stream->cancel, stream->global); if (!p->src) { archive_entry_close(stream); diff --git a/stream/stream_memory.c b/stream/stream_memory.c index 7b1092a76d..01246cf33f 100644 --- a/stream/stream_memory.c +++ b/stream/stream_memory.c @@ -86,7 +86,7 @@ struct stream *stream_memory_open(struct mpv_global *global, void *data, int len struct stream_open_args sargs = { .global = global, .url = "memory://", - .flags = STREAM_READ | STREAM_SILENT, + .flags = STREAM_READ | STREAM_SILENT | STREAM_ORIGIN_DIRECT, .sinfo = &stream_info_memory, .special_arg = &(bstr){data, len}, }; diff --git a/stream/stream_smb.c b/stream/stream_smb.c index 33928d4e61..1e52b55a37 100644 --- a/stream/stream_smb.c +++ b/stream/stream_smb.c @@ -151,4 +151,5 @@ const stream_info_t stream_info_smb = { .open = open_f, .protocols = (const char*const[]){"smb", NULL}, .can_write = true, //who's gonna do that? + .stream_origin = STREAM_ORIGIN_FS, }; |