diff options
-rw-r--r-- | DOCS/man/options.rst | 20 | ||||
-rw-r--r-- | common/playlist.h | 3 | ||||
-rw-r--r-- | player/loadfile.c | 19 | ||||
-rw-r--r-- | stream/stream.c | 16 | ||||
-rw-r--r-- | stream/stream.h | 3 | ||||
-rw-r--r-- | stream/stream_file.c | 1 | ||||
-rw-r--r-- | stream/stream_lavf.c | 20 |
7 files changed, 54 insertions, 28 deletions
diff --git a/DOCS/man/options.rst b/DOCS/man/options.rst index 87f7eb54b2..d2b062109c 100644 --- a/DOCS/man/options.rst +++ b/DOCS/man/options.rst @@ -198,20 +198,12 @@ Playback Control (i.e. not with stdin, pipe, etc). ``--load-unsafe-playlists`` - Normally, something like ``mpv playlist.m3u`` won't load the playlist. This - is because the playlist code is unsafe. (This is the same in all other - variations of MPlayer.) - - See ``--playlist`` for details. - - Note: this option will allow opening playlists using the ``playlist`` - special demuxer. The ``--playlist`` uses different code, and supports more - playlist formats than the playlist demuxer. This means that for now, the - ``--playlist`` option should always be used if you intend to open playlists. - Background: the special demuxer contains newly written code, while the - ``--playlist`` option uses the old MPlayer code. Adding support for more - playlist formats to the special demuxer is work in progress, and eventually - the old code should disappear. + Load URLs from playlists which are considered unsafe (default: no). This + includes special protocols and anything that doesn't refer to normal files. + Local files and http links on the other hand are always considered safe. + + Note that ``--playlist`` always loads all entries, so you use that instead + if you really have the need for this functionality. ``--loop-file`` Loop a single file. The difference to ``--loop=inf`` is that this doesn't diff --git a/common/playlist.h b/common/playlist.h index ea0e3698a2..916d21bf45 100644 --- a/common/playlist.h +++ b/common/playlist.h @@ -41,6 +41,9 @@ struct playlist_entry { bool playback_short : 1; // Set to true if not at least 1 frame (audio or video) could be played. bool init_failed : 1; + // If set, assume that this is e.g. from an external playlist, and needs an + // additional safety check. + bool unsafe_origin : 1; }; struct playlist { diff --git a/player/loadfile.c b/player/loadfile.c index 3833a80231..e685c15b80 100644 --- a/player/loadfile.c +++ b/player/loadfile.c @@ -1084,7 +1084,10 @@ static void play_current_file(struct MPContext *mpctx) } stream_filename = mpctx->resolve_result->url; } - mpctx->stream = stream_open(stream_filename, mpctx->global); + int stream_flags = STREAM_READ; + if (mpctx->playlist->current->unsafe_origin && !opts->load_unsafe_playlists) + stream_flags |= STREAM_SAFE_ONLY; + mpctx->stream = stream_create(stream_filename, stream_flags, mpctx->global); if (!mpctx->stream) { // error... demux_was_interrupted(mpctx); goto terminate_playback; @@ -1127,16 +1130,10 @@ goto_reopen_demuxer: ; mpctx->initialized_flags |= INITIALIZED_DEMUXER; if (mpctx->demuxer->playlist) { - if (mpctx->demuxer->stream->safe_origin || opts->load_unsafe_playlists) { - transfer_playlist(mpctx, mpctx->demuxer->playlist); - } else { - MP_ERR(mpctx, "\nThis looks like a playlist, but playlist support " - "will not be used automatically.\nThe main problem with " - "playlist safety is that playlist entries can be arbitrary,\n" - "and an attacker could make mpv poke around in your local " - "filesystem or network.\nUse --playlist=file or the " - "--load-unsafe-playlists option to load them anyway.\n"); - } + struct playlist *pl = mpctx->demuxer->playlist; + for (struct playlist_entry *e = pl->first; e; e = e->next) + e->unsafe_origin |= !mpctx->demuxer->stream->safe_origin; + transfer_playlist(mpctx, pl); goto terminate_playback; } diff --git a/stream/stream.c b/stream/stream.c index cfb3cb6c82..226626cf3c 100644 --- a/stream/stream.c +++ b/stream/stream.c @@ -61,6 +61,7 @@ extern const stream_info_t stream_info_null; extern const stream_info_t stream_info_memory; extern const stream_info_t stream_info_mf; extern const stream_info_t stream_info_ffmpeg; +extern const stream_info_t stream_info_ffmpeg_unsafe; extern const stream_info_t stream_info_avdevice; extern const stream_info_t stream_info_file; extern const stream_info_t stream_info_ifo; @@ -77,6 +78,7 @@ static const stream_info_t *const stream_list[] = { &stream_info_cdda, #endif &stream_info_ffmpeg, + &stream_info_ffmpeg_unsafe, &stream_info_avdevice, #if HAVE_DVBIN &stream_info_dvb, @@ -257,6 +259,8 @@ static int open_internal(const stream_info_t *sinfo, struct stream *underlying, return STREAM_NO_MATCH; if (sinfo->stream_filter && (flags & STREAM_NO_FILTERS)) return STREAM_NO_MATCH; + if (!sinfo->is_safe && (flags & STREAM_SAFE_ONLY)) + return STREAM_UNSAFE; const char *path = NULL; // Stream filters use the original URL, with no protocol matching at all. @@ -335,18 +339,30 @@ struct stream *stream_create(const char *url, int flags, struct mpv_global *glob assert(url); // Open stream proper + bool unsafe = false; for (int i = 0; stream_list[i]; i++) { int r = open_internal(stream_list[i], NULL, url, flags, global, &s); if (r == STREAM_OK) break; if (r == STREAM_NO_MATCH || r == STREAM_UNSUPPORTED) continue; + if (r == STREAM_UNSAFE) { + unsafe = true; + continue; + } if (r != STREAM_OK) { mp_err(log, "Failed to open %s.\n", url); goto done; } } + if (!s && unsafe) { + mp_err(log, "\nRefusing to load potentially unsafe URL from a playlist.\n" + "Use --playlist=file or the --load-unsafe-playlists option to " + "load it anyway.\n\n"); + goto done; + } + if (!s) { mp_err(log, "No stream found to handle url %s\n", url); goto done; diff --git a/stream/stream.h b/stream/stream.h index a961267aac..94103962c9 100644 --- a/stream/stream.h +++ b/stream/stream.h @@ -55,7 +55,9 @@ enum streamtype { // flags for stream_open_ext (this includes STREAM_READ and STREAM_WRITE) #define STREAM_NO_FILTERS 2 +#define STREAM_SAFE_ONLY 4 +#define STREAM_UNSAFE -3 #define STREAM_NO_MATCH -2 #define STREAM_UNSUPPORTED -1 #define STREAM_ERROR 0 @@ -141,6 +143,7 @@ typedef struct stream_info_st { const char *const *url_options; bool stream_filter; bool can_write; + bool is_safe; } stream_info_t; typedef struct stream { diff --git a/stream/stream_file.c b/stream/stream_file.c index 12bea3554c..6a10114832 100644 --- a/stream/stream_file.c +++ b/stream/stream_file.c @@ -281,4 +281,5 @@ const stream_info_t stream_info_file = { .open = open_f, .protocols = (const char*const[]){ "file", "", NULL }, .can_write = true, + .is_safe = true, }; diff --git a/stream/stream_lavf.c b/stream/stream_lavf.c index 37c6adc51c..2270831b88 100644 --- a/stream/stream_lavf.c +++ b/stream/stream_lavf.c @@ -322,10 +322,24 @@ const stream_info_t stream_info_ffmpeg = { .name = "ffmpeg", .open = open_f, .protocols = (const char *const[]){ - "lavf", "ffmpeg", "rtmp", "rtsp", "http", "https", "mms", "mmst", "mmsh", - "mmshttp", "udp", "ftp", "rtp", "httpproxy", "hls", "rtmpe", "rtmps", - "rtmpt", "rtmpte", "rtmpts", "srtp", "tcp", "udp", "tls", "unix", "sftp", + "rtmp", "rtsp", "http", "https", "mms", "mmst", "mmsh", "mmshttp", "rtp", + "httpproxy", "hls", "rtmpe", "rtmps", "rtmpt", "rtmpte", "rtmpts", "srtp", "md5", NULL }, .can_write = true, + .is_safe = true, }; + +// Unlike above, this is not marked as safe, and can contain protocols which +// may do insecure things. (Such as "ffmpeg", which can access the "lavfi" +// pseudo-demuxer, which in turn gives access to filters that can access the +// local filesystem.) +const stream_info_t stream_info_ffmpeg_unsafe = { + .name = "ffmpeg", + .open = open_f, + .protocols = (const char *const[]){ + "lavf", "ffmpeg", "udp", "ftp", "tcp", "tls", "unix", "sftp", + NULL }, + .can_write = true, +}; + |